package com.slofzx.nuoda.evaluation.version.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.slofzx.nuoda.common.dto.PageDTO;
import com.slofzx.nuoda.common.enums.CommonResultEnum;
import com.slofzx.nuoda.common.enums.ServiceResult;
import com.slofzx.nuoda.common.exception.ServiceException;
import com.slofzx.nuoda.common.service.impl.BaseServiceImpl;
import com.slofzx.nuoda.common.util.DataConvertUtil;
import com.slofzx.nuoda.common.vo.FileVO;
import com.slofzx.nuoda.evaluation.compute.data.dao.ComputeDetailDataDAO;
import com.slofzx.nuoda.evaluation.compute.data.dto.ComputeDetailDataDTO;
import com.slofzx.nuoda.evaluation.compute.data.entity.ComputeDetailData;
import com.slofzx.nuoda.evaluation.compute.data.service.ComputeDetailDataService;
import com.slofzx.nuoda.evaluation.compute.data.vo.ComputeDetailDataVO;
import com.slofzx.nuoda.evaluation.core.enums.ComputeVersionMarkEnum;
import com.slofzx.nuoda.evaluation.core.enums.ExtraEvaluateMethodEnum;
import com.slofzx.nuoda.evaluation.core.enums.ResultEnum;
import com.slofzx.nuoda.evaluation.model.dto.TableDTO;
import com.slofzx.nuoda.evaluation.model.feign.ModelConfigClient;
import com.slofzx.nuoda.evaluation.project.dto.ProjectInfoDTO;
import com.slofzx.nuoda.evaluation.project.dto.ProjectReportDetailDTO;
import com.slofzx.nuoda.evaluation.project.entity.ProjectInfo;
import com.slofzx.nuoda.evaluation.project.enums.PassTypeEnum;
import com.slofzx.nuoda.evaluation.project.observer.BatchObserver;
import com.slofzx.nuoda.evaluation.project.service.ProjectReportDetailYearService;
import com.slofzx.nuoda.evaluation.project.vo.ProjectInfoVO;
import com.slofzx.nuoda.evaluation.ref.builder.AbstractComputeResultExtractBuilder;
import com.slofzx.nuoda.evaluation.ref.init.ModelExportItemLoader;
import com.slofzx.nuoda.evaluation.ref.service.ModelExportRefService;
import com.slofzx.nuoda.evaluation.ref.vo.ModelExportRefVO;
import com.slofzx.nuoda.evaluation.version.builder.ComputeResultExtractBuilder;
import com.slofzx.nuoda.evaluation.version.dao.ComputeVersionDAO;
import com.slofzx.nuoda.evaluation.version.dto.ComputeVersionDTO;
import com.slofzx.nuoda.evaluation.version.entity.ComputeVersion;
import com.slofzx.nuoda.evaluation.version.service.ComputeVersionService;
import com.slofzx.nuoda.evaluation.version.service.ModelKeyItemRefService;
import com.slofzx.nuoda.evaluation.dto.*;
import com.slofzx.nuoda.evaluation.entity.*;
import com.slofzx.nuoda.evaluation.enums.ComputeVersionTypeEnum;
import com.slofzx.nuoda.evaluation.model.enums.YearDataFillTypeEnum;
import com.slofzx.nuoda.evaluation.feign.ComputeInvokeClient;
import com.slofzx.nuoda.evaluation.model.feign.TableClient;
import com.slofzx.nuoda.evaluation.project.dao.ProjectInfoDAO;
import com.slofzx.nuoda.evaluation.project.observer.ProjectObserver;
import com.slofzx.nuoda.evaluation.version.vo.ProjectComputeVersionLockVO;
import com.slofzx.nuoda.evaluation.model.vo.*;
import com.slofzx.nuoda.evaluation.vo.ComputeResultVO;
import com.slofzx.nuoda.evaluation.vo.MonteCarloAnalysisResultVO;
import com.slofzx.nuoda.excel.service.ExcelService;
import com.slofzx.nuoda.excel.vo.ExcelPreviewDataVO;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import com.slofzx.nuoda.evaluation.version.vo.ComputeVersionVO;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 评价信息服务实现类
 *
 * @author nuoda
 * @since 2021-11-19 15:56:06
 */
@Service("computeVersionService")
public class ComputeVersionServiceImpl extends BaseServiceImpl implements ComputeVersionService, ProjectObserver, BatchObserver {
    @Resource
    protected ComputeVersionDAO computeVersionDAO;
    @Resource
    protected ComputeDetailDataDAO computeDetailDataDAO;
    @Autowired
    protected ExcelService excelService;
    @Resource
    protected ModelConfigClient modelConfigClient;
    @Autowired
    private ProjectReportDetailYearService projectReportDetailYearService;

//    @Autowired
//    protected ComputeVersionDataService computeVersionDataService;

    //    @Autowired
//    private CustomFileUtil customFileUtil;
    @Autowired
    protected RestTemplate rawRestTemplate;

    @Resource
    protected ComputeInvokeClient computeInvokeClient;

    @Autowired
    protected TableClient tableClient;

    @Autowired
    protected ComputeDetailDataService computeDetailDataService;

    @Autowired
    protected ModelKeyItemRefService modelKeyItemRefService;

    @Resource
    protected ProjectInfoDAO projectInfoDAO;
    private static final String VERSION_PREFIX = "评价版本V";

    //    @Value("${nuoda.evaluation.oil-model-id}")
//    protected String oilModelId;
//    @Value("${nuoda.evaluation.gas-model-id}")
//    protected String gasModelId;
    @Resource
    private TaskExecutor taskExecutor;

    @Autowired
    private ModelExportRefService modelExportRefService;

    @Autowired
    private ModelExportItemLoader modelExportItemLoader;

    /**
     * 将数据表数据转换为返回数据类型
     *
     * @param entity 数据表对应类
     * @return 实例对象
     */
    protected ComputeVersionVO parseEntity2VO(ComputeVersion entity) {
        ComputeVersionVO vo = new ComputeVersionVO();
        vo.setId(entity.getId());
        vo.setName(entity.getName());
        vo.setProjectId(entity.getProjectId());
        vo.setModelId(entity.getModelId());
        vo.setBuildYearCount(entity.getBuildYearCount());
        vo.setCalculateYearStart(entity.getCalculateYearStart());
        vo.setCalculateYearEnd(entity.getCalculateYearEnd());
        vo.setRemark(entity.getRemark());
        vo.setType(entity.getType());
        vo.setIrrBeforeTax(entity.getIrrBeforeTax());
        vo.setIrrAfterTax(entity.getIrrAfterTax());
        vo.setPbpBeforeTax(entity.getPbpBeforeTax());
        vo.setPbpAfterTax(entity.getPbpAfterTax());
        vo.setNpvBeforeTax(entity.getNpvBeforeTax());
        vo.setNpvAfterTax(entity.getNpvAfterTax());
        vo.setCreateUser(entity.getCreateUser());
        vo.setCreateTime(entity.getCreateTime());
        vo.setReportTime(entity.getReportTime());
        vo.setCutoff(entity.isCutoff());
        vo.setParentId(entity.getParentId());
        vo.setEconomicLimitYear(entity.getEconomicLimitYear());
        vo.setMark(entity.getMark());
        vo.setRelated1(entity.getRelated1());
        vo.setRelated2(entity.getRelated2());
        vo.setComputeTime(entity.getComputeTime());
        vo.setCostPull(entity.isCostPull());
        vo.setTotalInvest(entity.getTotalInvest());
        vo.setPassed(entity.getPassed());
        vo.setConstructionInvest(entity.getConstructionInvest());
        vo.setUnitOperateCostDollar(entity.getUnitOperateCostDollar());
        vo.setUnitTotalOperateCostDollar(entity.getUnitTotalOperateCostDollar());
        vo.setTotalOperateCostDollar(entity.getTotalOperateCostDollar());
        vo.setOperateCostDollar(entity.getOperateCostDollar());
        vo.setOilCommodityVolumeDollar(entity.getOilCommodityVolumeDollar());
        vo.setUnitTotalOperateCost(entity.getUnitTotalOperateCost());
        vo.setUnitOperateCost(entity.getUnitOperateCost());
        vo.setBalanceConstructionInvest(entity.getBalanceConstructionInvest());
        vo.setBalanceSumGasOutput(entity.getBalanceSumGasOutput());
        vo.setBalanceSumOilOutput(entity.getBalanceSumOilOutput());
        return vo;
    }

    /**
     * 将数据传递类转换为数据表数据类
     *
     * @param dto 数据传递类实例
     * @return 实例对象
     */
    protected ComputeVersion parseDTO2Entity(ComputeVersionDTO dto) {
        ComputeVersion entity = new ComputeVersion();
        entity.setId(dto.getId());
        entity.setName(dto.getName());
        entity.setRelated1(dto.getRelated1());
        entity.setRelated2(dto.getRelated2());
        entity.setProjectId(dto.getProjectId());
        entity.setModelId(dto.getModelId());
        entity.setBuildYearCount(dto.getBuildYearCount());
        entity.setCalculateYearStart(dto.getCalculateYearStart());
        entity.setCalculateYearEnd(dto.getCalculateYearEnd());
        entity.setRemark(dto.getRemark());
        entity.setUnitOperateCost(dto.getUnitOperateCost());
        entity.setUnitTotalOperateCost(dto.getUnitTotalOperateCost());
        entity.setType(dto.getType());
        entity.setIrrBeforeTax(dto.getIrrBeforeTax());
        entity.setIrrAfterTax(dto.getIrrAfterTax());
        entity.setPbpBeforeTax(dto.getPbpBeforeTax());
        entity.setPbpAfterTax(dto.getPbpAfterTax());
        entity.setNpvBeforeTax(dto.getNpvBeforeTax());
        entity.setNpvAfterTax(dto.getNpvAfterTax());
        entity.setCutoff(dto.isCutoff());
        entity.setMark(dto.getMark());
        entity.setParentId(dto.getParentId());
        entity.setSourceId(dto.getSourceId());
        entity.setVersionNum(dto.getVersionNum());
        entity.setParamVersion(dto.getParamVersion());
        entity.setBatchId(dto.getBatchId());
        entity.setPassed(dto.getPassed());
        entity.setConstructionInvest(dto.getConstructionInvest());
        entity.setUnitOperateCostDollar(dto.getUnitOperateCostDollar());
        entity.setUnitTotalOperateCostDollar(dto.getUnitTotalOperateCostDollar());
        entity.setTotalOperateCostDollar(dto.getTotalOperateCostDollar());
        entity.setOperateCostDollar(dto.getOperateCostDollar());
        entity.setOilCommodityVolumeDollar(dto.getOilCommodityVolumeDollar());
        entity.setBalanceConstructionInvest(dto.getBalanceConstructionInvest());
        entity.setBalanceSumGasOutput(dto.getBalanceSumGasOutput());
        entity.setBalanceSumOilOutput(dto.getBalanceSumOilOutput());
        return entity;
    }

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public ComputeVersionVO queryById(String id) {
        ComputeVersion entity = this.computeVersionDAO.selectById(id);
        if (entity == null) {
            return null;
        }
        ComputeVersionDTO dto = new ComputeVersionDTO();
        dto.setParentId(id);
        List<ComputeVersionVO> dataList = queryList(dto);
        ComputeVersionVO vo = parseEntity2VO(entity);
        vo.setChildren(dataList);
        return vo;
    }

    @Override
    public ComputeVersion queryRawById(String id) {
        return computeVersionDAO.selectById(id);
    }

    /**
     * 查询多条数据
     *
     * @param dto 数据传递类实例对象
     * @return 对象列表
     */
    @Override
    public List<ComputeVersionVO> queryList(ComputeVersionDTO dto) {
//        List<ComputeVersionVO> dataList = this.computeVersionDAO.queryVOList(dto);
        //拿到dataList数据
        List<ComputeVersion> dataList = this.computeVersionDAO.queryList(dto);
        if (null == dataList || dataList.isEmpty()) {
            return Collections.emptyList();
        }
        //定义返回数组
        List<ComputeVersionVO> resultList = new ArrayList(dataList.size());
        Set<String> idSet = new HashSet<>();
        //复制到返回数组中
        for (ComputeVersion item : dataList) {
            ComputeVersionVO vo = parseEntity2VO(item);
            vo.setName(vo.getName()+"-V"+item.getVersionNum());
            resultList.add(vo);
            idSet.add(item.getId());
        }

        //处理children数据
        ComputeVersionDTO childrenQueryDTO = new ComputeVersionDTO();
        childrenQueryDTO.setPageSize(PageDTO.ALL);
        childrenQueryDTO.setFilterParentSet(idSet);
        List<ComputeVersion> childrenList = this.computeVersionDAO.queryList(childrenQueryDTO);
        Map<String, List<ComputeVersionVO>> childrenMap = new HashMap<>();
        if (childrenList != null) {
            for (ComputeVersion item : childrenList) {

                List<ComputeVersionVO> subList = childrenMap.get(item.getParentId());
                if (subList == null) {
                    subList = new ArrayList<>();
                    childrenMap.put(item.getParentId(), subList);
                }
                ComputeVersionVO vo = parseEntity2VO(item);
                subList.add(vo);

            }
        }
        //塞children数据
        for (ComputeVersionVO item : resultList) {
            item.setChildren(childrenMap.get(item.getId()));
        }
        return resultList;
    }

    /**
     * 查询多条数据
     *
     * @param dto 数据传递类实例对象
     * @return 对象列表
     */
    @Override
    public List<ComputeVersion> queryRawList(ComputeVersionDTO dto) {
//        List<ComputeVersionVO> dataList = this.computeVersionDAO.queryVOList(dto);
        return this.computeVersionDAO.queryList(dto);
    }

    /**
     * 创建版本
     * 创建版本信息，然后初始化版本输入数据
     *
     * @param dto 实例对象
     * @return 操作结果
     */
    @Transactional
    @Override
    public ServiceResult create(ComputeVersionDTO dto) {
//        if (StringUtils.isEmpty(dto.getProjectId())
//                || StringUtils.isEmpty(dto.getModelId())) {
//            return CommonResultEnum.VALUE_INVALID;
//        }
//        ProjectInfo projectInfo = projectInfoDAO.selectById(dto.getProjectId());
//        if(projectInfo == null) {
//            return CommonResultEnum.NOT_EXIST;
//        }
//        if (StringUtils.isNotEmpty(dto.getName())) {
//            dto.setName(dto.getName().trim());
//        }
//        //记录全部的评价版本信息
//        List<ComputeVersion> totalVersionList = new ArrayList<>();
//        if (ComputeVersionTypeEnum.getEnum(dto.getType()) == null) {
//            dto.setType(ComputeVersionTypeEnum.DEFAULT.getId());
//        }
//        SysUserVO userVO = getUser();
//        ComputeVersion entity = parseDTO2Entity(dto);
//        if (Objects.isNull(entity.getVersionNum())) {
//            Integer maxVersion = computeVersionDAO.getMaxVersionByProjectId(projectInfo.getId());
//            if (Objects.isNull(maxVersion)) {
//                maxVersion = 0;
//            }
//            entity.setVersionNum(++maxVersion);
//        }
//        if (StringUtils.isEmpty(entity.getName())) {
//            entity.setName(VERSION_PREFIX + entity.getVersionNum());
//        }
//        entity.setId(IdGen.uuid());
//        entity.setCreateTime(new Date());
//        entity.setCostPull(true);
//        if(userVO!=null) {
//            entity.setCreateUser(userVO.getId());
//        }
//        ProjectFeasibilityDataVO projectFeasibilityDataVO = feasibilityDataService.queryProjectData(projectInfo.getId());
//        CommonParamVersionDTO versionDTO = new CommonParamVersionDTO();
////        versionDTO.setYear(dto.getCostStandardYear());
////        versionDTO.setId(dto.getCostStandardVersion());
////        List<CommonParamVersionVO> costStandardVersionList = costStandardVersionService.queryList(versionDTO);
////        CommonParamVersionVO CommonParamVersionVO = null;
//        String costStandardVersion = dto.getCostStandardVersion();
//        if (StringUtils.isEmpty(costStandardVersion) && Objects.nonNull(projectFeasibilityDataVO.getHasProjectData()) && Objects.nonNull(projectFeasibilityDataVO.getHasProjectData().getData())) {
//            final Object standardVersion = projectFeasibilityDataVO.getHasProjectData().getData().get("cost_standard_version");
//            if (Objects.nonNull(standardVersion)) {
//                costStandardVersion = (String) standardVersion;
//            }
//        }
//        CommonParamVersionVO CommonParamVersionVO = costStandardVersionService.queryById(costStandardVersion);
////        if (costStandardVersionList != null || costStandardVersionList.size() > 0) {
////            CommonParamVersionVO = costStandardVersionList.get(0);
////        } else {
//        if(CommonParamVersionVO == null) {
//            CommonParamVersionVO = costStandardVersionService.queryLatestPublishVersion();
//        }
//        CostStandardOilPriceVO costStandardOilPriceVO = null;
//        //评价价格
//        OilPriceQueryDTO priceDTO = new OilPriceQueryDTO();
//        priceDTO.setVersion(CommonParamVersionVO.getId());
//        if(projectFeasibilityDataVO.getHasProjectData()!=null&&projectFeasibilityDataVO.getHasProjectData().getData()!=null) {
//            priceDTO.setOilGroup((String) projectFeasibilityDataVO.getHasProjectData().getData().get(FeasibilityParamEnum.OIL_GROUP.getId()));
//            priceDTO.setEvaluatePrice((String) projectFeasibilityDataVO.getHasProjectData().getData().get(FeasibilityParamEnum.EVALUATE_PRICE.getId()));
//            costStandardOilPriceVO = costStandardOilPriceService.queryValue(priceDTO);
//        }
//        if(costStandardOilPriceVO!=null) {
//            entity.setEvaPriceDollar(costStandardOilPriceVO.getDollarPrice());
//            entity.setEvaPriceYuan(costStandardOilPriceVO.getYuanPrice());
//        }
//
//        ExtraEvaluateMethodEnum evaluateType = ExtraEvaluateMethodEnum.getEnum(dto.getExtraEvaluateMethod());
//        boolean needInitData = true;
//        if (entity.getParentId() == null && ExtraEvaluateMethodEnum.SUBTRACT == evaluateType) {
//            entity.setExtraEvaluateMethod(dto.getExtraEvaluateMethod());
//            entity.setMark(ComputeVersionMarkEnum.RESULT.getId());
//            //对减版本不需要初始化数据
//            needInitData = false;
//        }
//        totalVersionList.add(entity);
//        if(dto.isAutoCompute() == false) {
//            //如果不进行自动计算，则进行插入操作，否则计算后统一插入
//            this.computeVersionDAO.insert(entity);
//        }
//
//
//
//        ProjectComputeInitData initData = projectFeasibilityInitDataHandler.generateInitData(projectInfo,projectFeasibilityDataVO,CommonParamVersionVO);
//        final List<ComputeDetailDataDTO> computeDetailDataDTOS = new ArrayList<>();
//        TableDTO tableDTO = new TableDTO();
//        tableDTO.setModelId(entity.getModelId());
//        tableDTO.setPageSize(PageDTO.ALL);
//        List<TableVO> tableList = tableClient.queryListWithField(tableDTO).getData();
//
//        ConcurrentMap<String,Map<String, Map<String, Map<Integer, String>>>> allInputDataCacheMap = new ConcurrentHashMap<>();
//        //创建版本数据
//        if (needInitData) {
//            computeDetailDataDTOS.add(initComputeDetailData(entity, initData.getHasProjectData(),tableList,allInputDataCacheMap));
//        }
//        List<ComputeVersion> wellVersionList = new ArrayList<>();
//        if(projectFeasibilityDataVO.getWellInfoList()!=null) {
//            //如果有项目包含井，需要创建井的计算版本，对需要评价的井进行评价
//            for (ProjectWellInfoVO well : projectFeasibilityDataVO.getWellInfoList()) {
////                WellMarkEnum wellMarkEnum = WellMarkEnum.getEnum(well.getMark());
//                if(!well.getEva()) {
//                    continue;
//                }
//                ComputeVersion wellComputeVersion = parseDTO2Entity(dto);
//                wellComputeVersion.setId(IdGen.uuid());
//                wellComputeVersion.setCreateTime(new Date());
//                if(userVO!=null) {
//                    wellComputeVersion.setCreateUser(userVO.getId());
//                }
//                wellComputeVersion.setParentId(entity.getId());
//                wellComputeVersion.setName(well.getCode());
//                wellComputeVersion.setWellId(well.getId());
//                wellComputeVersion.setProjectId(projectInfo.getId());
//                wellComputeVersion.setType(ComputeVersionTypeEnum.DEFAULT.getId());
//                wellComputeVersion.setMark("well");
//                wellComputeVersion.setRemark("单井");
//                if(costStandardOilPriceVO!=null) {
//                    wellComputeVersion.setEvaPriceDollar(costStandardOilPriceVO.getDollarPrice());
//                    wellComputeVersion.setEvaPriceYuan(costStandardOilPriceVO.getYuanPrice());
//                }
//                wellVersionList.add(wellComputeVersion);
//                totalVersionList.add(wellComputeVersion);
//            }
//            if (wellVersionList.size() > 0) {
//                if(dto.isAutoCompute() == false) {
//                    //如果不进行自动计算，则进行插入操作，否则计算后统一插入
//                    saveBatch(wellVersionList, computeVersionDAO, ComputeVersion.class);
//                }
//                Map<String, ComputeInitDataVO> wellInitDataMap = new HashMap<>();
//                for (ComputeInitDataVO item : initData.getWellDataList()) {
//                    wellInitDataMap.put(item.getId(), item);
//                }
//                for (ComputeVersion item : wellVersionList) {
//                    ComputeDetailDataDTO detailDataDTO = initComputeDetailData(item, wellInitDataMap.get(item.getWellId()), tableList, allInputDataCacheMap);
//                    computeDetailDataDTOS.add(detailDataDTO);
//                }
//            }
//
//        }
//        dto.setId(entity.getId());
//        ComputeVersion versionNoProject = null;
//        ComputeVersion versionNoProjectCostPull = null;
//        ComputeVersion versionHasProject = null;
//        if (ExtraEvaluateMethodEnum.SUBTRACT == evaluateType) {
//            //如果是老区项目，则新建两个子版本，有项目、无项目
//            versionHasProject = parseDTO2Entity(dto);
//            versionHasProject.setId(IdGen.uuid());
//            versionHasProject.setCreateUser(userVO.getId());
//            versionHasProject.setCreateTime(new Date());
//            versionHasProject.setParentId(entity.getId());
//            versionHasProject.setName(HAS_PROJECT_NAME);
//            versionHasProject.setType(ComputeVersionTypeEnum.DEFAULT.getId());
//            versionHasProject.setMark(ComputeVersionMarkEnum.HAS_PROJECT.getId());
//            versionHasProject.setRemark("老区项目有无对比-有项目");
//            if(costStandardOilPriceVO!=null) {
//                versionHasProject.setEvaPriceDollar(costStandardOilPriceVO.getDollarPrice());
//                versionHasProject.setEvaPriceYuan(costStandardOilPriceVO.getYuanPrice());
//            }
//            versionHasProject.setCostStandardVersion(CommonParamVersionVO.getId());
//            totalVersionList.add(versionHasProject);
//            if(dto.isAutoCompute() == false) {
//                //如果不进行自动计算，则进行插入操作，否则计算后统一插入
//                this.computeVersionDAO.insert(versionHasProject);
//            }
//            //创建版本数据
//            computeDetailDataDTOS.add(initComputeDetailData(versionHasProject, initData.getHasProjectData(),tableList,allInputDataCacheMap));
//
//            versionNoProject = parseDTO2Entity(dto);
//            versionNoProject.setId(IdGen.uuid());
//            versionNoProject.setCreateUser(userVO.getId());
//            versionNoProject.setCreateTime(new Date());
//            versionNoProject.setParentId(entity.getId());
//            versionNoProject.setName(NO_PROJECT_NAME);
//            versionNoProject.setType(ComputeVersionTypeEnum.DEFAULT.getId());
//            versionNoProject.setMark(ComputeVersionMarkEnum.NO_PROJECT.getId());
//            versionNoProject.setRemark("老区项目有无对比-无项目");
//            if(costStandardOilPriceVO!=null) {
//                versionNoProject.setEvaPriceDollar(costStandardOilPriceVO.getDollarPrice());
//                versionNoProject.setEvaPriceYuan(costStandardOilPriceVO.getYuanPrice());
//            }
//            versionNoProject.setCostStandardVersion(CommonParamVersionVO.getId());
//            totalVersionList.add(versionNoProject);
//            if(dto.isAutoCompute() == false) {
//                //如果不进行自动计算，则进行插入操作，否则计算后统一插入
//                this.computeVersionDAO.insert(versionNoProject);
//            }
//            //创建版本数据
//            computeDetailDataDTOS.add(initComputeDetailData(versionNoProject, initData.getNoProjectData(),tableList,allInputDataCacheMap));
//
//            entity.setRelated1(versionHasProject.getId());
//            entity.setRelated2(versionNoProject.getId());
//            if(dto.isAutoCompute() == false) {
//                //如果不进行自动计算，则进行更新操作，否则计算后统一插入
//                this.computeVersionDAO.updateById(entity);
//            }
//        }
//
//        if (dto.isAutoCompute()==false&& CollectionUtils.isNotEmpty(computeDetailDataDTOS)) {
//            if (computeDetailDataDTOS.size()>30) {
//                final List<List<ComputeDetailDataDTO>> partition = Lists.partition(computeDetailDataDTOS, 30);
//                for (List<ComputeDetailDataDTO> detailDataDTOS : partition) {
//                    computeDetailDataService.createBatch(detailDataDTOS);
//                }
//            } else {
//                computeDetailDataService.createBatch(computeDetailDataDTOS);
//            }
//        }
//        if(dto.isAutoCompute()) {
//            ModelConfigVO modelConfigVO = modelConfigClient.queryById(entity.getModelId(),"sys").getData();
//            Map<String, ModelExportRefVO> modelExportRefVOMap = modelExportRefService.queryModelExportRefMap(entity.getModelId());
//
//            int wellCount = 0;
//            if(wellVersionList!=null) {
//                wellCount = wellVersionList.size();
//            }
//            CountDownLatch countDownLatch = new CountDownLatch(wellCount);
//            if(wellVersionList.size()>0) {
//                for(ComputeVersion wellVersion:wellVersionList) {
//                    taskExecutor.execute(() -> {
//                        try {
//                            ComputeVersionDTO wellDTO = new ComputeVersionDTO();
//                            wellDTO.setId(wellVersion.getId());
//                            wellDTO.setCutoff(wellVersion.isCutoff());
//                            wellDTO.setCalculateYearStart(wellVersion.getCalculateYearStart());
//                            wellDTO.setCalculateYearEnd(wellVersion.getCalculateYearEnd());
//                            wellDTO.setBuildYearCount(wellVersion.getBuildYearCount());
//                            wellDTO.setModelId(wellVersion.getModelId());
////                        wellDTO.setDataMap(computeDetailDataService.getComputeData(wellVersion.getId()).getInputDataMap());
//                            wellDTO.setDataMap(allInputDataCacheMap.get(wellVersion.getId()));
//                            ServiceResult result = computeResult(wellDTO,wellVersion,modelConfigVO,modelExportRefVOMap);
//                            if (result != CommonResultEnum.SUCCESS) {
//                                logger.error("自动评价单井失败，项目:{},单井:{}", projectInfo, wellVersion);
//                            }
//                        }catch (Exception e) {
//                            logger.error("自动评价单井异常，项目:{},单井:{}", projectInfo, wellVersion,e);
//                        } finally {
//                            countDownLatch.countDown();
//                        }
//                    });
//                }
//            }
//            ServiceResult computeResult = null;
//            //需等到单井计算完成再生成报告
//            dto.setGenerateReport(false);
//            if (ExtraEvaluateMethodEnum.SUBTRACT == evaluateType) {
//                //如果是老区项目，则新建两个子版本，有项目、无项目
//                versionNoProjectCostPull = parseDTO2Entity(dto);
//                versionNoProjectCostPull.setId(IdGen.uuid());
//                versionNoProjectCostPull.setCreateUser(userVO.getId());
//                versionNoProjectCostPull.setCreateTime(new Date());
//                versionNoProjectCostPull.setParentId(entity.getId());
//                versionNoProjectCostPull.setName(NO_PROJECT_CP_NAME);
//                versionNoProjectCostPull.setType(ComputeVersionTypeEnum.DEFAULT.getId());
//                versionNoProjectCostPull.setMark(ComputeVersionMarkEnum.NO_PROJECT_COST_PULL.getId());
//                versionNoProjectCostPull.setRemark("老区项目有无对比-无项目(已拉齐)");
//                versionNoProjectCostPull.setCutoff(dto.isCutoff());
//                if (costStandardOilPriceVO != null) {
//                    versionNoProjectCostPull.setEvaPriceDollar(costStandardOilPriceVO.getDollarPrice());
//                    versionNoProjectCostPull.setEvaPriceYuan(costStandardOilPriceVO.getYuanPrice());
//                }
//                versionNoProjectCostPull.setCostStandardVersion(CommonParamVersionVO.getId());
//                totalVersionList.add(versionNoProjectCostPull);
////                this.computeVersionDAO.insert(versionNoProjectCostPull);
//                entity.setRelated2(versionNoProjectCostPull.getId());
////                this.computeVersionDAO.updateById(entity);
//
//                dto.setRelated1(entity.getRelated1());
//                dto.setRelated2(versionNoProjectCostPull.getId());
//                dto.setCostPull(true);
//                computeResult = subtractResult(dto,entity,
//                        versionHasProject,versionNoProject,versionNoProjectCostPull,
//                        allInputDataCacheMap.get(versionHasProject.getId())
//                        ,allInputDataCacheMap.get(versionNoProject.getId())
//                        , modelConfigVO,modelExportRefVOMap);
//            } else {
//                //如果需要创建后自动计算，则执行计算逻辑
////                dto.setDataMap(computeDetailDataService.getComputeData(entity.getId()).getInputDataMap());
//                dto.setDataMap(allInputDataCacheMap.get(entity.getId()));
//                computeResult = computeResult(dto,entity,modelConfigVO,modelExportRefVOMap);
//            }
//            try {
//                countDownLatch.await(10, TimeUnit.SECONDS);
//            } catch (InterruptedException e) {
//                logger.error("并发处理单井计算信息数据中断错误！ 项目ID {}，错误信息: ", projectInfo.getId(), e);
//            }
//            //批量保存版本信息
//            saveBatch(totalVersionList,computeVersionDAO,ComputeVersion.class);
//            //异步生成报告
//            uploadFeasibilityReport(entity);
//            if(computeResult!=CommonResultEnum.SUCCESS) {
//                return computeResult;
//            }
//
//        }
        return CommonResultEnum.SUCCESS;
    }

    /**
     * 修改数据
     *
     * @param dto 实例对象
     * @return 操作结果
     */
    @Override
    public ServiceResult update(ComputeVersionDTO dto) {
        String id = dto.getId();
        if (StringUtils.isEmpty(id)) {
            return CommonResultEnum.NOT_EXIST;
        }
        if (StringUtils.isEmpty(dto.getModelId())) {
            return CommonResultEnum.VALUE_INVALID;
        }
        ComputeVersion entity = this.computeVersionDAO.selectById(id);
        if (entity == null) {
            return CommonResultEnum.NOT_EXIST;
        }
        ComputeVersionTypeEnum typeEnum = ComputeVersionTypeEnum.getEnum(dto.getType());
        entity.setName(dto.getName());
        entity.setRelated1(dto.getRelated1());
        entity.setRelated2(dto.getRelated2());
//        if(typeEnum == ComputeVersionTypeEnum.TEMP) {
        //未保存版本可修改评价模型
        if (StringUtils.isEmpty(dto.getModelId())) {
            return CommonResultEnum.VALUE_INVALID;
        }
        entity.setModelId(dto.getModelId());
        entity.setBuildYearCount(dto.getBuildYearCount());
        entity.setCalculateYearStart(dto.getCalculateYearStart());
        entity.setCalculateYearEnd(dto.getCalculateYearEnd());
//        }
        if (typeEnum != null) {
            entity.setType(dto.getType());
        }
        entity.setRemark(dto.getRemark());
        entity.setIrrBeforeTax(dto.getIrrBeforeTax());
        entity.setIrrAfterTax(dto.getIrrAfterTax());
        entity.setPbpBeforeTax(dto.getPbpBeforeTax());
        entity.setPbpAfterTax(dto.getPbpAfterTax());
        entity.setNpvBeforeTax(dto.getNpvBeforeTax());
        entity.setNpvAfterTax(dto.getNpvAfterTax());
        entity.setCutoff(dto.isCutoff());
        entity.setConstructionInvest(dto.getConstructionInvest());
        entity.setUnitTotalOperateCostDollar(dto.getUnitTotalOperateCostDollar());
        entity.setTotalOperateCostDollar(dto.getTotalOperateCostDollar());
        entity.setOperateCostDollar(dto.getOperateCostDollar());
        entity.setOilCommodityVolumeDollar(dto.getOilCommodityVolumeDollar());
        entity.setUnitOperateCostDollar(dto.getUnitOperateCostDollar());
        entity.setBalanceConstructionInvest(dto.getBalanceConstructionInvest());
        entity.setBalanceSumGasOutput(dto.getBalanceSumGasOutput());
        entity.setBalanceSumOilOutput(dto.getBalanceSumOilOutput());
        this.computeVersionDAO.updateById(entity);
        //如果有子版本，则需要一块儿更新
        ComputeVersionDTO childDTO = new ComputeVersionDTO();
        childDTO.setParentId(entity.getId());
        List<ComputeVersion> childList = this.computeVersionDAO.queryList(childDTO);
        if (childList != null && childList.size() > 0) {
            for (ComputeVersion item : childList) {
                ComputeVersionDTO itemDTO = new ComputeVersionDTO();
                itemDTO.setName(item.getName());
                itemDTO.setId(item.getId());
                itemDTO.setRemark(item.getRemark());
                itemDTO.setParentId(entity.getId());
                itemDTO.setModelId(entity.getModelId());
                itemDTO.setCutoff(entity.isCutoff());
                itemDTO.setBuildYearCount(entity.getBuildYearCount());
                itemDTO.setCalculateYearStart(entity.getCalculateYearStart());
                itemDTO.setCalculateYearEnd(entity.getCalculateYearEnd());
                itemDTO.setSourceId(item.getSourceId());
                itemDTO.setMark(item.getMark());
                itemDTO.setProjectId(item.getProjectId());
                update(itemDTO);
            }
        }
        return CommonResultEnum.SUCCESS;
    }

    @Override
    public ServiceResult updateEntity(ComputeVersion entity) {
        this.computeVersionDAO.updateById(entity);
        return CommonResultEnum.SUCCESS;
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 操作结果
     */
    @Transactional
    @Override
    public ServiceResult deleteById(String id) {
        ComputeVersion version = computeVersionDAO.selectById(id);
        if (ComputeVersionTypeEnum.getEnum(version.getType()) != ComputeVersionTypeEnum.DEFAULT) {
            //非初评版不可人为删除
            throw new ServiceException("非初评版本无法删除", "非初评版本无法删除", version);
        }
        // TODO 添加校验逻辑，如数据权限
        this.computeVersionDAO.deleteById(id);
        ComputeVersionDTO dto = new ComputeVersionDTO();
        dto.setParentId(id);
        //删除版本数据
        this.computeDetailDataService.deleteById(id);
        //删除子版本
        List<ComputeVersion> children = this.computeVersionDAO.queryList(dto);
        if (children != null) {
            for (ComputeVersion child : children) {
                this.computeVersionDAO.deleteById(child.getId());
                computeDetailDataService.deleteById(child.getId());
//                computeVersionDataService.deleteByVersion(child.getId());
            }
        }
        return CommonResultEnum.SUCCESS;
    }

    @Transactional
    @Override
    public ServiceResult deleteByProject(String id) {
        ComputeVersionDTO dto = new ComputeVersionDTO();
        dto.setProjectId(id);
        List<ComputeVersion> dataList = computeVersionDAO.queryList(dto);
        computeVersionDAO.delete(dto);
//        ComputeVersion version = computeVersionDAO.selectById(id);
//        if (ComputeVersionTypeEnum.getEnum(version.getType()) != ComputeVersionTypeEnum.DEFAULT) {
//            //非初评版不可人为删除
//            return CommonResultEnum.PERMISSION_DENY;
//        }
//        this.computeVersionDAO.deleteById(id);
        if(dataList != null && !dataList.isEmpty()){
            List<String> idList = dataList.stream().map(ComputeVersion::getId).collect(Collectors.toList());
            LambdaQueryWrapper<ComputeDetailData> deleteDetailWra = new LambdaQueryWrapper<>();
            deleteDetailWra.in(ComputeDetailData::getId,idList);
            computeDetailDataDAO.delete(deleteDetailWra);
        }
        return CommonResultEnum.SUCCESS;
    }

    @Override
    @Transactional
    public ServiceResult deleteByBatch(String batchId) {
        ComputeVersionDTO dto = new ComputeVersionDTO();
        dto.setBatchId(batchId);
        List<ComputeVersion> dataList = computeVersionDAO.queryList(dto);
        computeVersionDAO.delete(dto);
        if(dataList != null && !dataList.isEmpty()){
            List<String> idList = dataList.stream().map(ComputeVersion::getId).collect(Collectors.toList());

            int pointsDataLimit = 500;//限制条数
            Integer size = idList.size();
            //判断是否有必要分批
            if (pointsDataLimit < size) {
                int part = size / pointsDataLimit;//分批数
                for (int i = 0; i < part; i++) {
                    List<String> listPage = idList.subList(0, pointsDataLimit);
                    LambdaQueryWrapper<ComputeDetailData> deleteDetailWra = new LambdaQueryWrapper<>();
                    deleteDetailWra.in(ComputeDetailData::getId,listPage);
                    computeDetailDataDAO.delete(deleteDetailWra);
                    idList.subList(0, pointsDataLimit).clear();
                }
                if (!idList.isEmpty()) {
                    LambdaQueryWrapper<ComputeDetailData> deleteDetailWra = new LambdaQueryWrapper<>();
                    deleteDetailWra.in(ComputeDetailData::getId,idList);
                    computeDetailDataDAO.delete(deleteDetailWra);
                }
            } else {
                LambdaQueryWrapper<ComputeDetailData> deleteDetailWra = new LambdaQueryWrapper<>();
                deleteDetailWra.in(ComputeDetailData::getId,idList);
                computeDetailDataDAO.delete(deleteDetailWra);
            }
        }
        return CommonResultEnum.SUCCESS;
    }

    @Override
    public ServiceResult delete(ComputeVersionDTO versionDTO) {
        if (StringUtils.isEmpty(versionDTO.getId()) && StringUtils.isEmpty(versionDTO.getProjectId())) {
            //不允许大批量删除，防止误操作
            return CommonResultEnum.PERMISSION_DENY;
        }
        computeVersionDAO.delete(versionDTO);
        return CommonResultEnum.SUCCESS;
    }

//    /**
//     * 保存为保存版本，使用未保存数据替换原有数据
//     * @param dto
//     * @return
//     */
//    @Transactional
//    @Override
//    public ServiceResult saveTemp(ComputeVersionDTO dto) {
//        //查询当前版本信息
//        ComputeVersion version = computeVersionDAO.queryById(dto.getId());
//        String tempVersionId = version.getId();
//        if(version == null) {
//            return CommonResultEnum.NOT_EXIST;
//        }
//        if(ComputeVersionTypeEnum.getEnum(version.getType())!=ComputeVersionTypeEnum.TEMP) {
//            //只处理未保存版本
//            return CommonResultEnum.SUCCESS;
//        }
//        //查询来源版本信息
//        ComputeVersion targetVersion = computeVersionDAO.queryById(version.getSourceId());
//        if(targetVersion == null) {
//            return CommonResultEnum.NOT_EXIST;
//        }
//        version.setId(targetVersion.getId());
//        version.setType(targetVersion.getType());
//        version.setSourceId(null);
//        computeVersionDAO.update(version);
//
//        //更新计算数据
//        ComputeData computeData = computeDataDAO.getComputeData(tempVersionId);
//        computeData.setId(targetVersion.getId());
//        computeDataDAO.updateComputeData(computeData);
//        //删掉原有未保存版本
//        computeVersionDAO.deleteById(tempVersionId);
//        computeDataDAO.deleteComputeDataById(tempVersionId);
//
//        //删除缓存文件
//        File tempVersionFile = customFileUtil.getComputeResultCacheFile(tempVersionId);
//        File targetVersionFile = customFileUtil.getComputeResultCacheFile(targetVersion.getId());
//        if(tempVersionFile!=null&&tempVersionFile.exists()) {
//            tempVersionFile.delete();
//        }
//        if(targetVersionFile!=null&&targetVersionFile.exists()) {
//            targetVersionFile.delete();
//        }
//
//        //删除原有版本数据
//        computeVersionDataService.deleteByVersion(targetVersion.getId());
//        //将未保存数据更新为原有版本数据
//        ServiceResult result = computeVersionDataService.transferVersion2Target(tempVersionId,targetVersion.getId());
//        if(result!=CommonResultEnum.SUCCESS) {
//            throw new ServiceException("数据保存失败","未保存版本数据转换失败",dto);
//        }
//
//        return CommonResultEnum.SUCCESS;
//    }

    @Transactional
    @Override
    public ServiceResult copy(ComputeVersionDTO dto) {
        if (StringUtils.isBlank(dto.getName())
                || StringUtils.isEmpty(dto.getProjectId())) {
            return CommonResultEnum.VALUE_INVALID;
        }
//        String modelId = dto.getModelId();
//        if(StringUtils.isBlank(modelId)) {
//
//        }
        ComputeVersion sourceVersion = computeVersionDAO.selectById(dto.getId());
        if (sourceVersion == null) {
            return CommonResultEnum.NOT_EXIST;
        }
        String newVersionId = copyFrom(sourceVersion, dto);
        ComputeVersionDTO childDTO = new ComputeVersionDTO();
        childDTO.setParentId(sourceVersion.getId());
        List<ComputeVersion> childList = computeVersionDAO.queryList(childDTO);
        ComputeVersion newVersion = computeVersionDAO.selectById(newVersionId);
        //复制子版本，注意对减版本还需要进行复制有无对减版本
        if (childList != null && childList.size() > 0) {
            for (ComputeVersion item : childList) {
                ComputeVersionDTO versionDTO = new ComputeVersionDTO();
                versionDTO.setName(item.getName());
                versionDTO.setRemark(item.getRemark());
                versionDTO.setCutoff(dto.isCutoff());
                versionDTO.setCalculateYearEnd(dto.getCalculateYearEnd());
                versionDTO.setCalculateYearStart(dto.getCalculateYearStart());
//                versionDTO.setModelId();
                String oldId = item.getId();
                item.setParentId(newVersionId);
                String newId = copyFrom(item, versionDTO);
                if (newVersion.getRelated1() != null && newVersion.getRelated1().equals(oldId)) {
                    newVersion.setRelated1(newId);
                }
                if (newVersion.getRelated2() != null && newVersion.getRelated2().equals(oldId)) {
                    newVersion.setRelated2(newId);
                }
            }
            computeVersionDAO.updateById(newVersion);
        }
        dto.setId(newVersionId);
        return CommonResultEnum.SUCCESS;
    }

    /**
     * 复制版本数据
     *
     * @param sourceVersion 原始版本
     * @param dto           新版本数据
     * @return 新版本id
     */
    public String copyFrom(ComputeVersion sourceVersion, ComputeVersionDTO dto) {
        ComputeVersion entity = JSON.parseObject(JSON.toJSONString(sourceVersion), ComputeVersion.class);
        entity.setName(dto.getName().trim());
        entity.setRemark(dto.getRemark());
        entity.setType(ComputeVersionTypeEnum.DEFAULT.getId());
        entity.setCalculateYearStart(dto.getCalculateYearStart());
        entity.setCalculateYearEnd(dto.getCalculateYearEnd());
        entity.setCutoff(dto.isCutoff());
        entity.setRemark(dto.getRemark());
//        if(ComputeVersionTypeEnum.getEnum(dto.getType()) == null) {
//            entity.setType(ComputeVersionTypeEnum.DEFAULT.getId());
//        }
        preInsert(entity);
        this.computeVersionDAO.insert(entity);
        //复制版本数据
        ComputeDetailDataVO sourceData = computeDetailDataService.queryById(sourceVersion.getId());
        if (sourceData != null) {
            ComputeDetailDataDTO dataDTO = new ComputeDetailDataDTO();
            dataDTO.setId(entity.getId());
            if (sourceData.getDetail() != null) {
                dataDTO.setDetail(sourceData.getDetail());
            }
            dataDTO.setMark(sourceData.getMark());
            dataDTO.setModelId(sourceData.getModelId());
            dataDTO.setSourceId(sourceData.getSourceId());
            dataDTO.setSourceType(sourceData.getSourceType());
            computeDetailDataService.create(dataDTO);
        }
        return entity.getId();
    }

    @Override
    public ServiceResult create(ComputeVersion version) {
        computeVersionDAO.insert(version);
        return CommonResultEnum.SUCCESS;
    }

    @Override
    public ServiceResult deleteByProjectAndMark(String projectId, String mark) {
        ComputeVersionDTO dto = new ComputeVersionDTO();
        dto.setProjectId(projectId);
        dto.setMark(mark);
        computeVersionDAO.delete(dto);
        return CommonResultEnum.SUCCESS;
    }

    @Override
    public ServiceResult saveComputeData(ComputeVersion version, ComputeData data) {
        version.setComputeTime(new Date());
        ModelConfigVO modelConfigVO = modelConfigClient.queryById(version.getModelId(), "sys").getData();
        KeyItemConfigVO modelKeyItemRefVO = modelConfigVO.getKeyItemConfig();
        if (modelKeyItemRefVO != null) {
            version.setIrrBeforeTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
                    .get(modelKeyItemRefVO.getIrrBeforeTax()))).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setIrrAfterTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
                    .get(modelKeyItemRefVO.getIrrAfterTax())))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setPbpBeforeTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
                    .get(modelKeyItemRefVO.getPbpBeforeTax())))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setPbpAfterTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
                    .get(modelKeyItemRefVO.getPbpAfterTax())))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setNpvBeforeTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
                    .get(modelKeyItemRefVO.getNpvBeforeTax())))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setNpvAfterTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
                    .get(modelKeyItemRefVO.getNpvAfterTax())))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setEconomicLimitYear(DataConvertUtil.parse2Int(data.getGroupDataMap().get("PJJZN"), null));
//        ModelKeyItemRefVO modelKeyItemRefVO = modelKeyItemRefService.queryByModel(version.getModelId());
//        if (modelKeyItemRefVO != null) {
//            version.setIrrBeforeTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                    .get(modelKeyItemRefVO.getIrrBeforeTax()))).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            version.setIrrAfterTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                    .get(modelKeyItemRefVO.getIrrAfterTax())))
//                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            version.setPbpBeforeTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                    .get(modelKeyItemRefVO.getPbpBeforeTax())))
//                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            version.setPbpAfterTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                    .get(modelKeyItemRefVO.getPbpAfterTax())))
//                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            version.setNpvBeforeTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                    .get(modelKeyItemRefVO.getNpvBeforeTax())))
//                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            version.setNpvAfterTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                    .get(modelKeyItemRefVO.getNpvAfterTax())))
//                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            if (modelKeyItemRefVO.getCutoffYear() != null) {
//                version.setEconomicLimitYear(DataConvertUtil.parse2Int(data.getGroupDataMap().get(modelKeyItemRefVO.getCutoffYear())));
//            }
        }

        updateEntity(version);

        ComputeDetailDataDTO dataDTO = new ComputeDetailDataDTO();
        dataDTO.setModelId(version.getModelId());
        dataDTO.setMark(version.getMark());
        dataDTO.setSourceId(version.getProjectId());
        dataDTO.setSourceType("project");
        dataDTO.setId(version.getId());
        if (data == null) {
            throw new ServiceException("计算数据不可为空，保存失败", "计算数据不可为空，保存失败", version);
        }
        dataDTO.setDetail(JSON.toJSONString(data));
        computeDetailDataService.save(dataDTO);
//        computeVersionDataService.saveComputeDataCache(version,data);
//        computeVersionDataService.saveComputeDataAsync(getUser(),version,data,templateDataConfig);
        return CommonResultEnum.SUCCESS;
    }

    /**
     * 计算结果，结果保存为未保存版本，一个项目只有一个未保存版本
     *
     * @param dto
     * @return
     */
    @Transactional
    @Override
    public ServiceResult computeResult(ComputeVersionDTO dto) {
        //查询版本信息
//        ComputeVersion version = createTempVersion(dto);
        ComputeVersion version = queryRawById(dto.getId());
        ComputeVersionTypeEnum typeEnum = ComputeVersionTypeEnum.getEnum(version.getType());
        if (typeEnum != ComputeVersionTypeEnum.DEFAULT) {
            //只允许初评版可以重新计算，其他版本不可重新计算
            return ResultEnum.COMPUTE_VERSION_TYPE_CANNOT_REINVOKE;
        }
        version.setCalculateYearEnd(dto.getCalculateYearEnd());
        version.setCalculateYearStart(dto.getCalculateYearStart());
        version.setBuildYearCount(dto.getBuildYearCount());
        version.setModelId(dto.getModelId());
        version.setCutoff(dto.isCutoff());

        ComputeInvokeDTO invokeDTO = new ComputeInvokeDTO();
        invokeDTO.setModelId(version.getModelId());
        invokeDTO.setCutoff(dto.isCutoff());
        invokeDTO.setExtraEvaluateMethod(dto.getExtraEvaluateMethod());
        invokeDTO.setCalculateYearStart(version.getCalculateYearStart());
        invokeDTO.setCalculateYearEnd(version.getCalculateYearEnd());
        invokeDTO.setBalanceAnalysis(true);
        invokeDTO.setBuildYearCount(version.getBuildYearCount());
        invokeDTO.setSensitivityAnalysis(true);
//        invokeDTO.setDataMap(computeDetailDataService.getComputeData(dto.getId()).getInputDataMap());
        invokeDTO.setDataMap(dto.getDataMap());
        ComputeResultVO data = computeInvokeClient.computeResult(invokeDTO).getData();
        if (data == null) {
            throw new ServiceException("计算失败", "调用计算服务计算失败", dto);
        }
       // ModelConfigVO modelConfigVO = modelConfigClient.queryById(version.getModelId(), "sys").getData();
        Map<String, ModelExportRefVO> modelExportRefVOMap = modelExportRefService.queryModelExportRefMap(version.getModelId());
        final ProjectInfo projectInfo = projectInfoDAO.selectById(version.getProjectId());
        ComputeResultExtractBuilder extractBuilder = new ComputeResultExtractBuilder(modelExportItemLoader.getDataList(),modelExportRefVOMap);
        extractBuilder.projectId(projectInfo.getId())
                .computeVersionId(version.getId())
                .computeResult(data);
        AbstractComputeResultExtractBuilder.Result extractResult = extractBuilder.build();
        updateVersionResult(version, (ProjectReportDetailDTO) extractResult.getReportDetail());
//        updateVersionResult(version, data, modelConfigVO,modelExportRefVOMap);
        saveComputeDetailData(version, invokeDTO.getDataMap(), data);
        // 基建井数
        version.setInfWellCount(projectInfo.getInfWellCount());
        // 新建产能  ==》 项目录入的建成能力
        version.setNewCapacity(projectInfo.getBuiltUpCapacity());
        //computeVersionDAO.insert(version);
        // 更新项目最终版本
        projectInfo.setComputeId(version.getId());
        //final String projectId = projectInfo.getId();
        projectInfoDAO.updateById(projectInfo);
        projectReportDetailYearService.batchSave(extractResult.getYearDataList(),getUserId());
//        saveProjectDetailYear(projectId,version.getId(),data,modelExportRefVOMap,extractResult);
        computeVersionDAO.updateById(version);
        return CommonResultEnum.SUCCESS;
    }

//    /**
//     * 保存导出用年份数据
//     * @param projectId
//     * @param computeVersionId
//     * @param data
//     * @param modelExportRefVOMap
//     */
//    private void saveProjectDetailYear(String projectId, String computeVersionId, ComputeResultVO data, Map<String, ModelExportRefVO> modelExportRefVOMap) {
//        //ZCZCB 总操作陈本
//        // SDSHJXJLL 税后净现金流
//        //JLR 净利润
//        // LRZE 利润总额
//        final Map<String, Map<Integer, Object>> allYearDataMap = data.getAllYearDataMap();
//        if (MapUtils.isEmpty(allYearDataMap)) {
//            return;
//        }
//        Map<Integer,ProjectReportDetailYearDTO> map = new HashMap<>();
//        final ProjectReportDetailYearDTO dto = new ProjectReportDetailYearDTO();
//        final ModelExportRefVO totalOpeateCost = modelExportRefVOMap.get(ProjectReportItemEnum.TOTAL_OPERATE_COST.getId());
//        if (totalOpeateCost!=null) {
//            final Map<Integer, Object> integerObjectMap = allYearDataMap.get(totalOpeateCost.getSourceId());
//            if (MapUtils.isNotEmpty(integerObjectMap)) {
//                for (Map.Entry<Integer, Object> entry : integerObjectMap.entrySet()) {
//                    final ProjectReportDetailYearDTO projectReportDetailYearDTO = new ProjectReportDetailYearDTO();
//                    projectReportDetailYearDTO.setTotalOperateCost(DataConvertUtil.parse2Double(entry.getValue()));
//                    projectReportDetailYearDTO.setYear(entry.getKey());
//                    projectReportDetailYearDTO.setComputeVersionId(computeVersionId);
//                    projectReportDetailYearDTO.setProjectId(projectId);
//                    map.put(entry.getKey(),projectReportDetailYearDTO);
//                }
//            }
//        }
//        final ModelExportRefVO totalNetProfitYearVO = modelExportRefVOMap.get(ProjectReportItemEnum.TOTAL_NET_PROFIT_YEAR.getId());
//        if (totalNetProfitYearVO!=null) {
//            final Map<Integer, Object> integerObjectMap = allYearDataMap.get(totalNetProfitYearVO.getSourceId());
//            if (MapUtils.isNotEmpty(integerObjectMap)) {
//                for (Map.Entry<Integer, Object> entry : integerObjectMap.entrySet()) {
//                    ProjectReportDetailYearDTO detailYearDTO = map.get(entry.getKey());
//                    if (Objects.isNull(detailYearDTO)) {
//                        detailYearDTO = new ProjectReportDetailYearDTO();
//                        detailYearDTO.setYear(entry.getKey());
//                        detailYearDTO.setComputeVersionId(computeVersionId);
//                        detailYearDTO.setProjectId(projectId);
//                        map.put(entry.getKey(),detailYearDTO);
//                    }
//                    detailYearDTO.setTotalNetProfit(DataConvertUtil.parse2Double(entry.getValue()));
//                }
//            }
//        }
//        final ModelExportRefVO netProfitYearVO = modelExportRefVOMap.get(ProjectReportItemEnum.NET_PROFIT_AFTER_TAX_YEAR.getId());
//        if (netProfitYearVO!=null) {
//            final Map<Integer, Object> integerObjectMap = allYearDataMap.get(netProfitYearVO.getSourceId());
//            if (MapUtils.isNotEmpty(integerObjectMap)) {
//                for (Map.Entry<Integer, Object> entry : integerObjectMap.entrySet()) {
//                    ProjectReportDetailYearDTO detailYearDTO = map.get(entry.getKey());
//                    if (Objects.isNull(detailYearDTO)) {
//                        detailYearDTO = new ProjectReportDetailYearDTO();
//                        detailYearDTO.setYear(entry.getKey());
//                        detailYearDTO.setComputeVersionId(computeVersionId);
//                        detailYearDTO.setProjectId(projectId);
//                        map.put(entry.getKey(),detailYearDTO);
//                    }
//                    detailYearDTO.setNetProfit(DataConvertUtil.parse2Double(entry.getValue()));
//                }
//            }
//        }
//
//        final ModelExportRefVO outPutYearRefVO = modelExportRefVOMap.get(ProjectReportItemEnum.OIL_OUTPUT_YEAR.getId());
//        if (outPutYearRefVO!=null) {
//            final Map<Integer, Object> integerObjectMap = allYearDataMap.get(outPutYearRefVO.getSourceId());
//            if (MapUtils.isNotEmpty(integerObjectMap)) {
//                for (Map.Entry<Integer, Object> entry : integerObjectMap.entrySet()) {
//                    ProjectReportDetailYearDTO detailYearDTO = map.get(entry.getKey());
//                    if (Objects.isNull(detailYearDTO)) {
//                        detailYearDTO = new ProjectReportDetailYearDTO();
//                        detailYearDTO.setYear(entry.getKey());
//                        detailYearDTO.setComputeVersionId(computeVersionId);
//                        detailYearDTO.setProjectId(projectId);
//                        map.put(entry.getKey(),detailYearDTO);
//                    }
//                    detailYearDTO.setOutPutYear(DataConvertUtil.parse2Double(entry.getValue()));
//                }
//            }
//        }
//
//        final ModelExportRefVO cashFlowRefVO = modelExportRefVOMap.get(ProjectReportItemEnum.CASH_FLOW_AFTER_TAX.getId());
//        if (cashFlowRefVO!=null) {
//            final Map<Integer, Object> integerObjectMap = allYearDataMap.get(cashFlowRefVO.getSourceId());
//            if (MapUtils.isNotEmpty(integerObjectMap)) {
//                for (Map.Entry<Integer, Object> entry : integerObjectMap.entrySet()) {
//                    ProjectReportDetailYearDTO detailYearDTO = map.get(entry.getKey());
//                    if (Objects.isNull(detailYearDTO)) {
//                        detailYearDTO = new ProjectReportDetailYearDTO();
//                        detailYearDTO.setYear(entry.getKey());
//                        detailYearDTO.setComputeVersionId(computeVersionId);
//                        detailYearDTO.setProjectId(projectId);
//                        map.put(entry.getKey(),detailYearDTO);
//                    }
//                    detailYearDTO.setCashFlowAfterTax(DataConvertUtil.parse2Double(entry.getValue()));
//                }
//            }
//        }
//        // 批量保存年份数据
//        final Collection<ProjectReportDetailYearDTO> values = map.values();
//        projectReportDetailYearService.batchSave(values);
//    }

    @Transactional
    public ProjectInfo saveAndComputeResult(ComputeVersionDTO dto,Map<String, ModelExportRefVO> modelExportRefVOMap,String userId) {
        ComputeVersion version = parseDTO2Entity(dto);
        preInsert(version);
        if(dto.getId()!=null) {
            version.setId(dto.getId());
        }
        version.setCalculateYearEnd(dto.getCalculateYearEnd());
        version.setCalculateYearStart(dto.getCalculateYearStart());
        version.setBuildYearCount(dto.getBuildYearCount());
        version.setModelId(dto.getModelId());
        version.setCutoff(dto.isCutoff());
        version.setBaseIrr(dto.getBaseIrr());
        version.setTotalInvest(dto.getTotalInvest());
        ComputeInvokeDTO invokeDTO = new ComputeInvokeDTO();
        invokeDTO.setModelId(version.getModelId());
        invokeDTO.setCutoff(dto.isCutoff());
        invokeDTO.setExtraEvaluateMethod(dto.getExtraEvaluateMethod());
        invokeDTO.setCalculateYearStart(version.getCalculateYearStart());
        invokeDTO.setCalculateYearEnd(version.getCalculateYearEnd());
        invokeDTO.setBalanceAnalysis(true);
        invokeDTO.setBuildYearCount(version.getBuildYearCount());
        invokeDTO.setSensitivityAnalysis(true);
//        invokeDTO.setDataMap(computeDetailDataService.getComputeData(dto.getId()).getInputDataMap());
        invokeDTO.setDataMap(dto.getDataMap());
        ComputeResultVO data = computeInvokeClient.computeResult(invokeDTO).getData();
        if (data == null) {
            throw new ServiceException("计算失败", "调用计算服务计算失败", dto);
        }
        final ProjectInfo projectInfo = projectInfoDAO.selectById(version.getProjectId());
        ComputeResultExtractBuilder extractBuilder = new ComputeResultExtractBuilder(modelExportItemLoader.getDataList(),modelExportRefVOMap);
        extractBuilder.projectId(projectInfo.getId())
                .computeVersionId(version.getId())
                .computeResult(data);
        AbstractComputeResultExtractBuilder.Result extractResult = extractBuilder.build();
        updateVersionResult(version, (ProjectReportDetailDTO) extractResult.getReportDetail());
//        updateVersionResult(version, data, modelConfigVO,modelExportRefVOMap);
        saveComputeDetailData(version, invokeDTO.getDataMap(), data);

        // 基建井数
        version.setInfWellCount(projectInfo.getInfWellCount());
        // 新建产能  ==》 项目录入的建成能力
        version.setNewCapacity(projectInfo.getBuiltUpCapacity());
        computeVersionDAO.insert(version);
        // 更新项目最终版本
        projectInfo.setUltimate(dto.isUltimate());
        projectInfo.setComputeId(version.getId());
        projectReportDetailYearService.batchSave(extractResult.getYearDataList(),userId);
//        saveProjectDetailYear(projectInfo.getId(),version.getId(),data,modelExportRefVOMap,extractResult);
       // projectInfoDAO.updateById(projectInfo);
        return projectInfo;
    }

    @Override
    public ExcelPreviewDataVO previewComputeResult(String dataVersion) {
        ComputeData computeData = computeDetailDataService.getComputeData(dataVersion);
        if (computeData == null) {
            return null;
        }
        ResponseEntity<byte[]> responseBody = computeInvokeClient.generateExcel(computeData);
        if (responseBody == null || responseBody.getBody() == null) {
            return null;
        }
        byte[] excelData = responseBody.getBody();
        if (excelData == null) {
            return null;
        }
        return excelService.previewDownloadWorkbook(excelData);
    }

    @Override
    public FileVO downloadComputeResult(String dataVersion) {
        ComputeVersionVO computeVersionVO = queryById(dataVersion);
        FileVO fileVO = getComputeResultCacheFile(computeVersionVO);
        return fileVO;
    }

    @Override
    public MonteCarloAnalysisResultVO computeMontecaloResult(String dataVersion, Map<String, MonteCarloItemDTO> config) {
        ComputeVersion version = queryRawById(dataVersion);
        if (version == null) {
            return null;
        }
        Map<String, Map<String, Map<Integer, String>>> inputDataMap = computeDetailDataService.getComputeInputDataMap(dataVersion);
        if (inputDataMap == null) {
            return null;
        }

        ComputeInvokeDTO invokeDTO = new ComputeInvokeDTO();
        invokeDTO.setMonteCarloConfig(config);
        invokeDTO.setDataMap(inputDataMap);
        invokeDTO.setCalculateYearStart(version.getCalculateYearStart());
        invokeDTO.setCalculateYearEnd(version.getCalculateYearEnd());
        invokeDTO.setCutoff(version.isCutoff());
        invokeDTO.setBuildYearCount(version.getBuildYearCount());
        invokeDTO.setModelId(version.getModelId());
        invokeDTO.setId(version.getId());
        return computeInvokeClient.monteCarloResult(invokeDTO).getData();
    }

    public ServiceResult initVersionData(ComputeVersion entity, Map<String, Object> projectDataMap) {
//        获取初始化数据
//        Map<String,Object> dataMap = getInitDataMap(entity.getProjectId(),entity.getCostStandardYear());
        //获取评价模型输入信息
//        List<TableVO> tableList=tableService.queryListWithField(entity.getModelId());
        TableDTO tableDTO = new TableDTO();
        tableDTO.setModelId(entity.getModelId());
        tableDTO.setPageSize(PageDTO.ALL);
        List<TableVO> tableList = tableClient.queryListWithField(tableDTO).getData();
        if (tableList == null || tableList.isEmpty()) {
            return CommonResultEnum.SUCCESS;
        }
        Map<String, Map<String, Map<Integer, String>>> inputDataMap = new HashMap<>(); //放入物map
        Map<String, Object> defaultValueSourceDataMap = new HashMap<>();  //默认值来源数据map
        if (projectDataMap != null) {
            for (String key : projectDataMap.keySet()) {  //遍历projectDataMap的key
                if (projectDataMap.get(key) instanceof List || projectDataMap.get(key) instanceof Array) {
                    List<Map<String, Object>> initDataMapList = (List<Map<String, Object>>) projectDataMap.get(key); //遍历projectDataMap中的value
                    if (initDataMapList.size() > 1) {
                        boolean find = false;
                        //如果初始化数据有多份，则按照mark标记匹配
                        for (Map<String, Object> dataItem : initDataMapList) {   //遍历value中的数据
                            String mark = (String) dataItem.get("mark");
                            if (Objects.equals(mark, entity.getMark())) {
                                defaultValueSourceDataMap.put(key, dataItem);
                                find = true;
                                break;
                            }
                        }
                        if (find == false) {
                            //如果没有匹配，则为空对象
                            defaultValueSourceDataMap.put(key, new HashMap<>());
                        }
                    } else {
                        defaultValueSourceDataMap.put(key, initDataMapList.get(0));
                    }
                } else {
                    defaultValueSourceDataMap.put(key, projectDataMap.get(key));
                }
            }
        }

        for (TableVO table : tableList) {
            List<FieldVO> inputFieldList = table.getFieldList();
            Map<String, Map<Integer, String>> tableData = inputDataMap.get(table.getId()); //inputDataMap为新数据
            if (tableData == null) {
                tableData = new HashMap<>();
                inputDataMap.put(table.getId(), tableData);
            }

            for (FieldVO field : inputFieldList) { //遍历表格每一列
                Map<Integer, String> fieldData = tableData.get(field.getId());
                if (fieldData == null) {
                    fieldData = new HashMap<>();
                    tableData.put(field.getId(), fieldData); //给inputDataMap遍历的tableData填充字段
                }

                //字段默认填充值
                String fieldDefaultFillValue = "";
                YearDataFillTypeEnum fillTypeEnum = YearDataFillTypeEnum.getEnum(field.getDataFillType());
                Map<String, Map<String, Object>> yearInitDataMap = new HashMap<>();
                if ("input".equals(field.getDefaultValueSource()) || StringUtils.isEmpty(field.getDefaultValueSource())) {
                    //如果默认值来源是自定义输入或者为空,则直接取默认值
                    if (StringUtils.isNotEmpty(field.getDefaultValue())) {
                        fieldDefaultFillValue = field.getDefaultValue();
                    }
                } else if (defaultValueSourceDataMap.containsKey(field.getDefaultValueSource())) {
                    //使用额外数据对字段进行默认值初始化
                    Map<String, Object> initDataMap = (Map<String, Object>) defaultValueSourceDataMap.get(field.getDefaultValueSource());
                    if (initDataMap.containsKey("yearDataList")) {
                        List<Map<String, Object>> yearDataList = (List<Map<String, Object>>) initDataMap.get("yearDataList");
                        for (Map<String, Object> item : yearDataList) {
                            yearInitDataMap.put(item.get("year") + "", item);
                        }
                    }
                    if (initDataMap.get(field.getDefaultValue()) != null) {
                        fieldDefaultFillValue = initDataMap.get(field.getDefaultValue()) + "";
                    }
                }

                fieldData.put(-1, fieldDefaultFillValue);
                if (table.isNeedLastYear()) {
                    String value = "";
                    //如果需要上年数据，且默认值填充方式为已发生年份或所有年份包含已发生则填充
                    if (YearDataFillTypeEnum.HAPPENED_YEAR == fillTypeEnum || YearDataFillTypeEnum.ALL_YEAR_WITH_HAPPENED == fillTypeEnum) {
                        value = fieldDefaultFillValue;
                    }
                    fieldData.put(entity.getCalculateYearStart() - 1, value);
                }

                //评价期年份数据填充
                int yearIndex = 0;
                //需要包含已发生年份
                for (int j = entity.getCalculateYearStart() - 1; j <= entity.getCalculateYearEnd(); j++) {
                    yearIndex = j - entity.getCalculateYearStart() + 1;
                    String value = "";
                    //如果当前年份为第一年而且默认值填充方式为第一年，则设为默认值
                    if (j == entity.getCalculateYearStart() && fillTypeEnum == YearDataFillTypeEnum.FIRST_YEAR) {
                        value = fieldDefaultFillValue;
                    }
                    //如果默认值填充方式为所有年份、所有年份包含已发生年份，设为默认值
                    if (fillTypeEnum == YearDataFillTypeEnum.ALL_YEAR || fillTypeEnum == YearDataFillTypeEnum.ALL_YEAR_WITH_HAPPENED) {
                        value = fieldDefaultFillValue;
                    }
                    String yearIndexKey = yearIndex + "";
                    if (yearInitDataMap.get(yearIndexKey) != null && yearInitDataMap.get(yearIndexKey).get(field.getDefaultValue()) != null) {
                        value = yearInitDataMap.get(yearIndexKey).get(field.getDefaultValue()) + "";
                    }
                    fieldData.put(j, value);
                }
            }
        }
        ComputeData data = new ComputeData();
        data.setId(entity.getId());
        data.setModelId(entity.getModelId());
        data.setVersion(entity.getCreateTime().getTime() + "");
        data.setInputDataMap(inputDataMap);
        data.setCutOff(entity.isCutoff());
        data.setProjectId(entity.getProjectId());
        data.setCreateTime(entity.getCreateTime());
        ComputeDetailDataDTO dataDTO = new ComputeDetailDataDTO();
        dataDTO.setModelId(entity.getModelId());
        dataDTO.setMark(entity.getMark());
        dataDTO.setSourceId(entity.getProjectId());
        dataDTO.setSourceType("project");
        dataDTO.setId(entity.getId());
        if (data == null) {
            throw new ServiceException("计算数据不可为空，保存失败", "计算数据不可为空，保存失败", entity);
        }
        dataDTO.setDetail(JSON.toJSONString(data));
        computeDetailDataService.save(dataDTO);
        return CommonResultEnum.SUCCESS;
    }

    /**
     * 获取计算结果缓存文件
     *
     * @param version
     * @return
     */
    public FileVO getComputeResultCacheFile(ComputeVersionVO version) {
        String fileName = "result.xls";
        try {
            fileName = new String((version.getName() + ".xls").getBytes("utf-8"), "ISO8859-1");
        } catch (UnsupportedEncodingException e) {
            logger.error("文件名称转换失败: {}", version);
        }
        FileVO fileVO = new FileVO();
        fileVO.setName(fileName);
        ComputeData computeData = computeDetailDataService.getComputeData(version.getId());
        ResponseEntity<byte[]> responseBody = computeInvokeClient.generateExcel(computeData);
        if (responseBody == null || responseBody.getBody() == null) {
            return null;
        }
        byte[] excelData = responseBody.getBody();
        if (excelData == null) {
            return null;
        }
        fileVO.setData(excelData);

        return fileVO;
    }

    @Transactional
    @Override
    public ServiceResult cashFlowPull(ComputeVersionDTO dto) {
        //查询无项目为拉齐版本信息
        ComputeVersion noProjectVersion = queryRawById(dto.getId());
        if (noProjectVersion == null) {
            return CommonResultEnum.NOT_EXIST;
        }
        ComputeVersionVO parentVersion = queryById(dto.getParentId());
        if (parentVersion == null || parentVersion.getChildren() == null) {
            return CommonResultEnum.NOT_EXIST;
        }
        ComputeVersionVO hasProjectVersion = null;
        for (ComputeVersionVO item : parentVersion.getChildren()) {
            if (ComputeVersionMarkEnum.getEnum(item.getMark()) == ComputeVersionMarkEnum.HAS_PROJECT) {
                hasProjectVersion = item;
                break;
            }
        }
        if (hasProjectVersion == null) {
            throw new ServiceException("有项目版本未计算,无法拉齐", "有项目版本未计算,无法拉齐", dto);
        }
        ComputeInvokeDTO invokeDTO = new ComputeInvokeDTO();
        invokeDTO.setDataMap(dto.getDataMap());
        invokeDTO.setCalculateYearStart(hasProjectVersion.getCalculateYearStart());
        invokeDTO.setCalculateYearEnd(hasProjectVersion.getCalculateYearEnd());
        invokeDTO.setCutoff(hasProjectVersion.isCutoff());
        invokeDTO.setBuildYearCount(hasProjectVersion.getBuildYearCount());
        invokeDTO.setModelId(hasProjectVersion.getModelId());
        invokeDTO.setId(hasProjectVersion.getId());
        invokeDTO.setDataMap(computeDetailDataService.getComputeInputDataMap(hasProjectVersion.getId()));
        ComputeVersion version = new ComputeVersion();
        preInsert(version);
        version.setName("无项目(已拉齐)");
        version.setRemark("有无项目对比无项目成本拉齐后结果");
        version.setMark(ComputeVersionMarkEnum.NO_PROJECT_COST_PULL.getId());
        version.setType(ComputeVersionTypeEnum.DEFAULT.getId());
        version.setParentId(noProjectVersion.getParentId());
        version.setProjectId(noProjectVersion.getProjectId());
        version.setModelId(noProjectVersion.getModelId());
        version.setCalculateYearStart(noProjectVersion.getCalculateYearStart());
        version.setBuildYearCount(noProjectVersion.getBuildYearCount());
        version.setComputeTime(new Date());
        int realEndYear = noProjectVersion.getCalculateYearEnd();
        version.setCalculateYearEnd(realEndYear);
        Map<String, Map<String, Map<Integer, String>>> noProjectInputDataMap = computeDetailDataService.getComputeInputDataMap(noProjectVersion.getId());
        invokeDTO.setNoProjectDataMap(noProjectInputDataMap);
        ComputeData computeData = computeInvokeClient.cashFlowPull(invokeDTO).getData();
        if (computeData == null) {
            throw new ServiceException("拉取计算失败", "调用计算服务进行拉齐计算失败", invokeDTO);
        }
        computeData.setId(version.getId());
        computeData.setProjectId(version.getProjectId());
        saveComputeData(version, computeData);
        deleteByProjectAndMark(version.getProjectId(), ComputeVersionMarkEnum.NO_PROJECT_COST_PULL.getId());
        create(version);
        dto.setId(version.getId());
        return CommonResultEnum.SUCCESS;
    }


    @Override
    public String getName() {
        return "project-compute-version";
    }

    @Override
    public ServiceResult handleBatchDelete(String batchId) {
        return deleteByBatch(batchId);
    }

    @Override
    public ServiceResult handleProjectCreate(String projectId) {
        return CommonResultEnum.SUCCESS;
    }


    @Override
    public ServiceResult handleProjectDelete(String projectId) {
        return deleteByProject(projectId);
    }

    /**
     * 有无项目对减
     * 有项目数据减去无项目拉齐后数据
     *
     * @param dto
     * @return
     */
    @Transactional
    @Override
    public ServiceResult subtractResult(ComputeVersionDTO dto) {
        ComputeVersion version = queryRawById(dto.getId());
        ComputeVersionDTO queryDTO = new ComputeVersionDTO();

        if (version == null) {
            return CommonResultEnum.NOT_EXIST;
        }
        queryDTO.setParentId(dto.getId());

        List<ComputeVersion> children = queryRawList(queryDTO);
        if (children == null || children.isEmpty()) {
            return CommonResultEnum.NOT_EXIST;
        }

        List<ComputeVersion> updateList = new ArrayList<>();
        updateList.add(version);

        ModelConfigVO modelConfigVO = modelConfigClient.queryById(version.getModelId(), "sys").getData();
        //有项目、无项目、无项目拉齐版本修改为只能各有一个
        ComputeVersion hasProjectVersion = null, noProjectVersion = null, noProjectCostPullVersion = null;
        for (ComputeVersion item : children) {
            ComputeVersionMarkEnum markEnum = ComputeVersionMarkEnum.getEnum(item.getMark());
            if (ComputeVersionMarkEnum.NO_PROJECT_COST_PULL == markEnum) {
                noProjectCostPullVersion = item;
                if (dto.isCostPull()) {
                    updateList.add(item);
                }
            } else if (ComputeVersionMarkEnum.NO_PROJECT == markEnum) {
                noProjectVersion = item;
                updateList.add(item);
            } else if (ComputeVersionMarkEnum.HAS_PROJECT == markEnum) {
                hasProjectVersion = item;
                updateList.add(item);
            }
        }
        //有项目输入数据
        Map<String, Map<String, Map<Integer, String>>> hasProjectData = computeDetailDataService.getComputeInputDataMap(hasProjectVersion.getId());
        //无项目输入数据
        Map<String, Map<String, Map<Integer, String>>> noProjectData = computeDetailDataService.getComputeInputDataMap(noProjectVersion.getId());
        ServiceResult result = subtractResult(dto, version
                , hasProjectVersion, noProjectVersion
                , noProjectCostPullVersion, hasProjectData, noProjectData, modelConfigVO);

        if (result != CommonResultEnum.SUCCESS) {
            return result;
        }


        updateBatchById(updateList, computeVersionDAO, ComputeVersion.class);
        if (noProjectCostPullVersion != null && !dto.isCostPull()) {
            deleteById(noProjectCostPullVersion.getId());
        }
        return CommonResultEnum.SUCCESS;
    }

    /**
     * 有无项目对减
     * 有项目数据减去无项目拉齐后数据
     *
     * @param dto
     * @return
     */
    @Transactional
    public ServiceResult subtractResult(ComputeVersionDTO dto, ComputeVersion version
            , ComputeVersion hasProjectVersion
            , ComputeVersion noProjectVersion
            , ComputeVersion noProjectCostPullVersion
            , Map<String, Map<String, Map<Integer, String>>> hasProjectData
            , Map<String, Map<String, Map<Integer, String>>> noProjectData
            , ModelConfigVO modelConfigVO) {
        if (version == null) {
            return CommonResultEnum.NOT_EXIST;
        }

        boolean costPull = dto.isCostPull();


        if (hasProjectVersion == null) {
            throw new ServiceException("无法找到有项目版本", "有无项目对减无法计算，缺少有项目版本", version);
        }
        if (noProjectVersion == null) {
            throw new ServiceException("无法找到无项目版本", "有无项目对减无法计算，缺少有无项目版本", version);
        }

        if (hasProjectData == null) {
            throw new ServiceException("有项目版本未评价，无法计算", "有无项目对减有项目版本未评价，无法计算", version);
        }
        if (noProjectData == null) {
            throw new ServiceException("无项目版本未评价，无法计算", "有无项目对减无项目拉齐版本未评价，无法计算", version);
        }
        ComputeInvokeDTO invokeDTO = new ComputeInvokeDTO();
        invokeDTO.setNoProjectDataMap(noProjectData);
        invokeDTO.setDataMap(hasProjectData);
        invokeDTO.setBalanceAnalysis(true);
        invokeDTO.setSensitivityAnalysis(true);
        invokeDTO.setExtraEvaluateMethod(ExtraEvaluateMethodEnum.SUBTRACT.getId());
        invokeDTO.setModelId(version.getModelId());
        invokeDTO.setCutoff(dto.isCutoff());
        invokeDTO.setCalculateYearStart(dto.getCalculateYearStart());
        invokeDTO.setCalculateYearEnd(dto.getCalculateYearEnd());
        invokeDTO.setNoProjectCostPull(costPull);
        Map<String, ComputeResultVO> resultVOMap = computeInvokeClient.subtractResultMap(invokeDTO).getData();
        ComputeResultVO resultVO = resultVOMap.get("result");
        version.setCutoff(dto.isCutoff());
        version.setCostPull(dto.isCostPull());
        version.setCalculateYearStart(dto.getCalculateYearStart());
        version.setCalculateYearEnd(dto.getCalculateYearEnd());
        version.setRelated1(dto.getRelated1());
        version.setRelated2(dto.getRelated2());
        //  version.setCostPull(dto.isCostPull());
        Map<String, ModelExportRefVO> modelExportRefVOMap = modelExportRefService.queryModelExportRefMap(version.getModelId());
        ComputeResultExtractBuilder extractBuilder = new ComputeResultExtractBuilder(modelExportItemLoader.getDataList(),modelExportRefVOMap);
        extractBuilder.projectId(version.getProjectId())
                .computeVersionId(version.getId())
                .computeResult(resultVO);
        AbstractComputeResultExtractBuilder.Result extractResult = extractBuilder.build();
        updateVersionResult(version, (ProjectReportDetailDTO) extractResult.getReportDetail());
//        updateVersionResult(version, resultVO, modelConfigVO,modelExportRefVOMap);
        saveComputeDetailData(version, null, resultVO);
        hasProjectVersion.setCutoff(dto.isCutoff());
        hasProjectVersion.setCalculateYearStart(dto.getCalculateYearStart());
        hasProjectVersion.setCalculateYearEnd(dto.getCalculateYearEnd());
        noProjectVersion.setCostPull(dto.isCutoff());
        noProjectVersion.setCalculateYearStart(dto.getCalculateYearStart());
        noProjectVersion.setCalculateYearEnd(dto.getCalculateYearEnd());

        //更新有项目结果字段
        AbstractComputeResultExtractBuilder.Result hasProjectExtractResult = extractBuilder.computeVersionId(hasProjectVersion.getId()).computeResult(resultVOMap.get("has_project")).build();
        updateVersionResult(hasProjectVersion, (ProjectReportDetailDTO) hasProjectExtractResult.getReportDetail());
//        updateVersionResult(hasProjectVersion, resultVOMap.get("has_project"), modelConfigVO,modelExportRefVOMap);
        //保存有项目计算详情数据
        saveComputeDetailData(hasProjectVersion, hasProjectData, resultVOMap.get("has_project"));
        //更新无项目结果字段
        AbstractComputeResultExtractBuilder.Result noProjectExtractResult = extractBuilder.computeVersionId(noProjectVersion.getId()).computeResult(resultVOMap.get("no_project")).build();
        updateVersionResult(noProjectVersion, (ProjectReportDetailDTO) noProjectExtractResult.getReportDetail());
//        updateVersionResult(noProjectVersion, resultVOMap.get("no_project"), modelConfigVO,modelExportRefVOMap);
        //保存无项目结果数据
        saveComputeDetailData(noProjectVersion, noProjectData, resultVOMap.get("no_project"));
        if (costPull) {
            if (noProjectCostPullVersion == null) {
                noProjectCostPullVersion = new ComputeVersion();
                preInsert(noProjectCostPullVersion);
                noProjectCostPullVersion.setName("无项目(已拉齐)");
                noProjectCostPullVersion.setRemark("有无项目对比无项目成本拉齐后结果");
                noProjectCostPullVersion.setMark(ComputeVersionMarkEnum.NO_PROJECT_COST_PULL.getId());
                noProjectCostPullVersion.setType(ComputeVersionTypeEnum.DEFAULT.getId());
                noProjectCostPullVersion.setParentId(noProjectVersion.getParentId());
                noProjectCostPullVersion.setProjectId(noProjectVersion.getProjectId());
                noProjectCostPullVersion.setModelId(noProjectVersion.getModelId());
                noProjectCostPullVersion.setCalculateYearStart(noProjectVersion.getCalculateYearStart());
                noProjectCostPullVersion.setBuildYearCount(noProjectVersion.getBuildYearCount());
                noProjectCostPullVersion.setComputeTime(new Date());
                int realEndYear = noProjectVersion.getCalculateYearEnd();
                noProjectCostPullVersion.setCalculateYearEnd(realEndYear);
                create(noProjectCostPullVersion);
            } else {
                //如果是对减已拉齐版本，则需要更新拉齐版本数据
                Map<String, Map<String, Map<Integer, String>>> noProjectCostPullInput = new HashMap<>();
                ComputeResultVO inputResult = resultVOMap.get("no_project_cost_pull:input");
                Map<String, Object> inputData = inputResult.getGroupDataMap();
                if (inputResult != null && inputData != null) {
                    for (Map.Entry<String, Object> entry : inputData.entrySet()) {
                        noProjectCostPullInput.put(entry.getKey(), (Map<String, Map<Integer, String>>) entry.getValue());
                    }
                }
                //更新无项目拉齐结果版本字段
                AbstractComputeResultExtractBuilder.Result pullExtractResult = extractBuilder.computeVersionId(noProjectVersion.getId()).computeResult(resultVOMap.get("no_project_cost_pull")).build();
                updateVersionResult(noProjectCostPullVersion, (ProjectReportDetailDTO) pullExtractResult.getReportDetail());
//                updateVersionResult(noProjectCostPullVersion, resultVOMap.get("no_project_cost_pull"), modelConfigVO,modelExportRefVOMap);
                //保存无项目拉齐结果数据
                saveComputeDetailData(noProjectCostPullVersion, noProjectCostPullInput, resultVOMap.get("no_project_cost_pull"));
            }
        }
        // 对减的版本肯定是项目版本，不需要判断是否是项目版本

        return CommonResultEnum.SUCCESS;
    }


//    /**
//     * 计算完成后更新版本结果数据,只是更新实体字段数据，不做数据库更新
//     *
//     * @param version       版本信息
//     * @param modelConfigVO 模型配置数据
//     * @return
//     */
//    public ServiceResult updateVersionResult(ComputeVersion version, ComputeResultVO data, ModelConfigVO modelConfigVO, Map<String, ModelExportRefVO> modelExportRefVOMap) {
//
//        version.setComputeTime(new Date());
//        KeyItemConfigVO modelKeyItemRefVO = modelConfigVO.getKeyItemConfig();
//        if (modelKeyItemRefVO != null) {
//            ModelExportRefVO irrBeforeTaxRefVO = modelExportRefVOMap.get(ProjectReportItemEnum.IRR_BEFORE_TAX.getId());
//            if (irrBeforeTaxRefVO != null) {
//                version.setIrrBeforeTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                        .get(irrBeforeTaxRefVO.getSourceId()))).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            }
//            ModelExportRefVO irrAfterTaxRefVO = modelExportRefVOMap.get(ProjectReportItemEnum.IRR_AFTER_TAX.getId());
//            if (irrAfterTaxRefVO != null) {
//                version.setIrrAfterTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                        .get(irrAfterTaxRefVO.getSourceId())))
//                        .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            }
//            // 净利润
//            ModelExportRefVO netProfitAfterTax = modelExportRefVOMap.get(ProjectReportItemEnum.NET_PROFIT_AFTER_TAX.getId());
//            if (netProfitAfterTax != null) {
//                version.setNetProfit(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                        .get(netProfitAfterTax.getSourceId())))
//                        .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            }
//            // 总投资
//            ModelExportRefVO totalInvestRefVO = modelExportRefVOMap.get(ProjectReportItemEnum.TOTAL_INVEST.getId());
//            if (totalInvestRefVO != null) {
//                version.setTotalInvest(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                        .get(totalInvestRefVO.getSourceId())))
//                        .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            }
//            ModelExportRefVO pbpBeforeTax = modelExportRefVOMap.get(ProjectReportItemEnum.PBP_BEFORE_TAX.getId());
//            if (pbpBeforeTax != null) {
//                version.setPbpBeforeTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                        .get(pbpBeforeTax.getSourceId())))
//                        .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            }
//            ModelExportRefVO pbpAfterTax = modelExportRefVOMap.get(ProjectReportItemEnum.PBP_AFTER_TAX.getId());
//            if (pbpAfterTax != null) {
//                version.setPbpAfterTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                        .get(pbpAfterTax.getSourceId())))
//                        .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            }
//            ModelExportRefVO npvBeforeTax = modelExportRefVOMap.get(ProjectReportItemEnum.NPV_BEFORE_TAX.getId());
//            if (npvBeforeTax != null) {
//                version.setNpvBeforeTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                        .get(npvBeforeTax.getSourceId())))
//                        .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            }
//            ModelExportRefVO npvAfterTaxRefVO = modelExportRefVOMap.get(ProjectReportItemEnum.NPV_AFTER_TAX.getId());
//            if (npvAfterTaxRefVO != null) {
//                version.setNpvAfterTax(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
//                        .get(npvAfterTaxRefVO.getSourceId())))
//                        .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            }
//            ModelExportRefVO economicLimitYearRefVO = modelExportRefVOMap.get(ProjectReportItemEnum.ECONOMIC_LIMIT_YEAR.getId());
////            version.setBalancePriceYuan(new BigDecimal(DataConvertUtil.parse2Double(data.getGroupDataMap()
////                    .get(modelKeyItemRefVO.getNpvAfterTax())))
////                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
//            if (economicLimitYearRefVO != null) {
//                version.setEconomicLimitYear(DataConvertUtil.parse2Int(
//                        data.getGroupDataMap().get(
//                                economicLimitYearRefVO.getSourceId()), null));
//            }
//        }
//        version.setPassed(version.getIrrAfterTax()>version.getBaseIrr()? PassTypeEnum.PASS.getId():PassTypeEnum.FAILED.getId());
//
//        return CommonResultEnum.SUCCESS;
//    }
    /**
     * 计算完成后更新版本结果数据,只是更新实体字段数据，不做数据库更新
     *
     * @param version       版本信息
     * @return
     */
    public ServiceResult updateVersionResult(ComputeVersion version, ProjectReportDetailDTO reportDetailDTO) {

        version.setComputeTime(new Date());
        if (reportDetailDTO != null) {
            version.setIrrBeforeTax(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getIrrBeforeTax())).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setIrrAfterTax(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getIrrAfterTax()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            // 净利润
            version.setNetProfit(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getNetProfitAfterTax()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            // 总投资
            version.setTotalInvest(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getTotalInvest()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            // 建设投资
            version.setConstructionInvest(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getConstructionInvest()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setPbpBeforeTax(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getPbpBeforeTax()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setPbpAfterTax(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getPbpAfterTax()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
                version.setNpvBeforeTax(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getNpvBeforeTax()))
                        .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
                version.setNpvAfterTax(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getNpvAfterTax()))
                        .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            if (reportDetailDTO.getEconomicLimitYear() != null) {
                version.setEconomicLimitYear(reportDetailDTO.getEconomicLimitYear());
            }
            version.setProjectDayOutput(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getProjectDayOutput()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setStraightOutput(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getStraightOutput()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setHorizontalDayOutput(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getHorizontalDayOutput()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setSumOilOutput(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getSumOilOutput()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setUnitOperateCostDollar(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getUnitOperateCostDollar()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setUnitTotalOperateCostDollar(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getUnitTotalOperateCostDollar()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setTotalOperateCostDollar(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getTotalOperateCostDollar()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setOperateCostDollar(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getOperateCostDollar()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setOilCommodityVolumeDollar(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getOilCommodityVolumeDollar()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setUnitOperateCost(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getUnitOperateCost()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setUnitTotalOperateCost(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getUnitTotalOperateCost()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setBalanceConstructionInvest(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getBalanceConstructionInvest()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setBalanceSumGasOutput(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getBalanceSumGasOutput()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
            version.setBalanceSumOilOutput(new BigDecimal(DataConvertUtil.parse2Double(reportDetailDTO.getBalanceSumOilOutput()))
                    .setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
        }
        version.setPassed(version.getIrrAfterTax()>version.getBaseIrr()? PassTypeEnum.PASS.getId():PassTypeEnum.FAILED.getId());

        return CommonResultEnum.SUCCESS;
    }

    /**
     * 保存详细数据
     *
     * @param version
     * @param inputDataMap
     * @param resultVO
     * @return
     */
    public ServiceResult saveComputeDetailData(ComputeVersion version, Map<String, Map<String, Map<Integer, String>>> inputDataMap, ComputeResultVO resultVO) {
        ComputeDetailDataDTO dataDTO = new ComputeDetailDataDTO();
        dataDTO.setModelId(version.getModelId());
        dataDTO.setMark(version.getMark());
        dataDTO.setSourceId(version.getProjectId());
        dataDTO.setSourceType("project");
        dataDTO.setId(version.getId());
        ComputeData data = parseResultVO2ComputeData(version, inputDataMap, resultVO);
        if (data == null) {
            throw new ServiceException("计算数据不可为空，保存失败", "计算数据不可为空，保存失败", version);
        }
        dataDTO.setDetail(JSON.toJSONString(data));
        computeDetailDataService.save(dataDTO);
        return CommonResultEnum.SUCCESS;
    }

    /**
     * 将ComputeResultVO转换为 ComputeData
     *
     * @param version
     * @param resultVO
     * @return
     */
    protected ComputeData parseResultVO2ComputeData(ComputeVersion version, Map<String, Map<String, Map<Integer, String>>> inputDataMap, ComputeResultVO resultVO) {

        ComputeData computeData = new ComputeData();
        computeData.setInputDataMap(inputDataMap);
        computeData.setId(version.getId());
        computeData.setCutOff(resultVO.isCutOff());
        computeData.setCalculateYearStart(resultVO.getCalculateYearStart());
        computeData.setCalculateYearEnd(resultVO.getCalculateYearEnd());
        computeData.setResultDataMap(resultVO.getAllYearDataMap());
        computeData.setGroupDataMap(resultVO.getGroupDataMap());
        computeData.setVersion(version.getId());
        computeData.setModelId(resultVO.getModelId());
        computeData.setProjectId(version.getProjectId());
        computeData.setSensAnalysisResult(resultVO.getSensAnalysisResult());
        computeData.setCreateTime(new Date());
        computeData.setBuildYearCount(resultVO.getBuildYearCount());

        return computeData;
    }

    //    @Override
//    public FileVO getMonteCarloDownloadFile(String dataVersion) {
//        ComputeVersion version = computeVersionService.queryRawById(dataVersion);
//        String projectId = version.getProjectId();
////        ProjectInfo project = projectInfoDAO.queryById(projectId);
//        FileVO fileVO = new FileVO();
////        fileVO.setName("("+project.getName()+")蒙特卡洛分析.xls");
//        fileVO.setName("蒙特卡洛分析结果.xls");
//        try {
//
//            fileVO.setData(FileCopyUtils.copyToByteArray(customFileUtil.getComputeResultCacheFile("montecarlo-"+dataVersion)));
//        } catch (IOException e) {
//            logger.error("生成excel预览数据失败.dataVersion:{} case:{}", dataVersion, e.getMessage(), e);
////            e.printStackTrace();
//        }
//        return fileVO;
//    }
    @Override
    public FileVO getMultiPriceComputeResultFile(String dataVersion, List<Double> priceList) {
        ComputeVersion version = queryRawById(dataVersion);
        if (version == null) {
            throw new ServiceException("未找到对应数据", "多油价计算无法找到当前计算版本", dataVersion);
        }
        ComputeVersionMarkEnum markEnum = ComputeVersionMarkEnum.getEnum(version.getMark());
        ComputeVersion noProjectVersion = null;
        if (markEnum == ComputeVersionMarkEnum.RESULT) {
            //如果是结果类型，认为是有无对减法计算
            version = queryRawById(version.getRelated1());
            if (version == null) {
                throw new ServiceException("未找到有项目对应数据", "多油价计算无法找到当前有项目计算版本", dataVersion);
            }
            noProjectVersion = queryRawById(version.getRelated2());
            if (noProjectVersion == null) {
                throw new ServiceException("未找到无项目对应数据", "多油价计算无法找到当前无项目计算版本", dataVersion);
            }
        }
        //获取保存的录入数据
//        Map<String,Map<String, Map<Integer,String>>>  inputData = computeVersionDataService.getComputeInputDataMap(version);
        Map<String, Map<String, Map<Integer, String>>> inputData = computeDetailDataService.getComputeInputDataMap(version.getId());
        if (inputData == null) {
            throw new ServiceException("未找到对应数据", "多油价计算无法找到当前计算版本", dataVersion);
        }
        //TODO 后续需要适配有无对减项目逻辑
        MultiPriceComputeInvokeDTO invokeDTO = new MultiPriceComputeInvokeDTO();
        invokeDTO.setCutoff(version.isCutoff());
        invokeDTO.setId("base");
        invokeDTO.setModelId(version.getModelId());
        invokeDTO.setBuildYearCount(version.getBuildYearCount());
        invokeDTO.setCalculateYearStart(version.getCalculateYearStart());
        invokeDTO.setCalculateYearEnd(version.getCalculateYearEnd());
        if (noProjectVersion != null) {
            Map<String, Map<String, Map<Integer, String>>> noProjectInputData = computeDetailDataService.getComputeInputDataMap(version.getId());
            invokeDTO.setNoProjectDataMap(noProjectInputData);
            invokeDTO.setExtraEvaluateMethod(ExtraEvaluateMethodEnum.SUBTRACT.getId());
            ComputeVersionMarkEnum noProjectMarkEnum = ComputeVersionMarkEnum.getEnum(noProjectVersion.getMark());
            if (noProjectMarkEnum == ComputeVersionMarkEnum.NO_PROJECT_COST_PULL) {
                //如果无项目版本是已拉齐版本，则需要进行成本拉齐
                invokeDTO.setNoProjectCostPull(true);
            }
        }
//        invokeDTO.setExtraEvaluateMethod(version.get);
        Map<String, Map<Integer, Double>> changePriceMap = new HashMap<>();
        for (int i = 0; i < priceList.size(); i++) {
            Map<Integer, Double> priceData = new HashMap<>();
            Double price = priceList.get(i);
            for (int year = version.getCalculateYearStart() - 1; year <= version.getCalculateYearEnd(); year++) {
                priceData.put(year, price);
            }
            changePriceMap.put(i + "", priceData);
        }
        invokeDTO.setChangePriceMap(changePriceMap);
        invokeDTO.setDataMap(inputData);
        Map<String, ComputeResultVO> multiPriceResult = computeInvokeClient.multiPriceResult(invokeDTO).getData();
        List<ComputeResultVO> resultVOList = new ArrayList<>();
        for (int i = 0; i < priceList.size(); i++) {
            ComputeResultVO resultVO = multiPriceResult.get(i + "");
            if (resultVO != null) {
                resultVOList.add(resultVO);
            }
        }
        byte[] fileData = computeInvokeClient.generateMultiPriceExcel(resultVOList).getBody();
        FileVO fileVO = new FileVO();
        fileVO.setName("多油价结果.xls");
        fileVO.setData(fileData);
        return fileVO;
    }

    /**
     * 查询当前项目评价版本最大版本号
     *
     * @param batchId
     * @return
     */
    @Override
    public Integer queryMaxVersionNum(String batchId) {
        if (StringUtils.isBlank(batchId)) {
            throw new ServiceException(CommonResultEnum.VALUE_INVALID, null, null);
        }
        return computeVersionDAO.getMaxVersionByBatchId(batchId);
    }

    @Override
    public ServiceResult batchComputeProjectResult(ModelConfigVO modelConfigVO, List<ComputeVersionDTO> totalVersionList) {
        if (totalVersionList == null || totalVersionList.isEmpty()) {
            return CommonResultEnum.SUCCESS;
        }
        Map<String, ModelExportRefVO> modelExportRefVOMap = modelExportRefService.queryModelExportRefMap(modelConfigVO.getKeyItemConfig().getModelId());
        CountDownLatch countDownLatch = new CountDownLatch(totalVersionList.size());
        List<ProjectInfo> projectInfoList =  Collections.synchronizedList(new ArrayList<>(totalVersionList.size()));

        String userId = getUserId();
        for (ComputeVersionDTO item : totalVersionList) {

            taskExecutor.execute(() -> {
                try {
                    if(item.getProjectId() == null) {
                        ComputeVersion version = parseDTO2Entity(item);
                        preInsert(version);
                        if(item.getId()!=null) {
                            version.setId(item.getId());
                        }
                        version.setComputeTime(new Date());
                        computeVersionDAO.insert(version);
                        return;
                    }
                    projectInfoList.add(saveAndComputeResult(item,modelExportRefVOMap,userId));
                } catch (Exception e) {
                    logger.error("评价任务 {} 项目评价异常，项目:{}", item.getBatchId(), item.getProjectId(), e);
                } finally {
                    countDownLatch.countDown();
                }
            });
        }

        try {
            countDownLatch.await(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            logger.error("并发处理单井计算信息数据中断错误！ 评价任务ID {}，错误信息: ", totalVersionList.get(0).getBatchId(), e);
        }
        if (CollectionUtils.isNotEmpty(projectInfoList)) {
            final List<List<ProjectInfo>> partition = Lists.partition(projectInfoList, 100);
            for (List<ProjectInfo> projectInfos : partition) {
                projectInfoDAO.updateBatchById(projectInfos);
            }
        }

        return CommonResultEnum.SUCCESS;
    }

    @Override
    public FileVO downloadComputeLog(String dataVersion) {
        ComputeVersion computeVersion = computeVersionDAO.selectById(dataVersion);
        ComputeDetailDataDTO dto = new ComputeDetailDataDTO();
        dto.setId(dataVersion);
        dto.setSourceType("project");
        ComputeDetailDataVO item = computeDetailDataService.queryById(dataVersion);
//        if (dataList == null || dataList.isEmpty()) {
//            return null;
//        }
//        List<FileVO> fileList = new ArrayList<>();
        int i = 1;
//        for (ComputeDetailDataVO item : dataList) {
        FileVO fileVO = new FileVO();
        byte[] fileData = item.getDetail().getBytes(StandardCharsets.UTF_8);
//            String markName = getComputeMarkName(item.getMark());
//            fileVO.setName(markName+".txt");
        fileVO.setName(computeVersion.getName()+"_计算日志.txt");
        fileVO.setData(fileData);
//            fileList.add(fileVO);
//        }
//        FileVO result = null;
//        try {
//            result = ZipFileUtil.compress(projectInfoVO.getName() + "计算日志.zip", fileList);
//        } catch (IOException e) {
//            logger.error("打包计算日志文件失败:{}", projectId, e);
//        }
        return fileVO;
    }

    /**
     * 查询锁定版本信息
     *
     * @param dto@return
     */
    @Override
    public List<ProjectComputeVersionLockVO> queryVersionData(ComputeVersionDTO dto) {
        if (StringUtils.isEmpty(dto.getBatchId())) {
            throw new ServiceException(CommonResultEnum.VALUE_INVALID,"任务id不存在",null);
        }
        final ProjectInfoDTO projectInfoDTO = new ProjectInfoDTO();
        projectInfoDTO.setBatchId(dto.getBatchId());
        projectInfoDTO.setPageNo(dto.getPageNo());
        projectInfoDTO.setPageSize(dto.getPageSize());
        projectInfoDTO.setName(dto.getName());
        final List<ProjectInfoVO> projectInfos = projectInfoDAO.queryVOList(projectInfoDTO);
        if (CollectionUtils.isEmpty(projectInfos)) {
            throw new ServiceException("任务不存在项目请先导入项目","任务不存在项目请先导入项目",null);
        }
        final ComputeVersionDTO versionDTO = new ComputeVersionDTO();
        final List<ComputeVersion> computeVersions = computeVersionDAO.queryList(versionDTO);
        if (CollectionUtils.isEmpty(computeVersions)) {
            throw new ServiceException("请先评价项目在锁定","请先评价项目在锁定",null);
        }
        final Map<String, List<ComputeVersion>> listMap = computeVersions.stream().filter(f-> StringUtils.isNotEmpty(f.getProjectId())).collect(Collectors.groupingBy(ComputeVersion::getProjectId));
        List<ProjectComputeVersionLockVO> versionLockVOS = new ArrayList<>();
        for (ProjectInfoVO projectInfo : projectInfos) {
            final ProjectComputeVersionLockVO vo = new ProjectComputeVersionLockVO();
            vo.setId(projectInfo.getId());
            vo.setName(projectInfo.getName());
            vo.setYear(projectInfo.getYear());
            vo.setComputeId(projectInfo.getComputeId());
            vo.setBuildOffice(projectInfo.getBuildOffice());
            vo.setIrrAfterTax(projectInfo.getIrrAfterTax());
            vo.setNpvAfterTax(projectInfo.getNpvAfterTax());
            vo.setPbpAfterTax(projectInfo.getPbpAfterTax());
            vo.setTotalInvest(projectInfo.getTotalInvest());
            final List<ComputeVersion> versions = listMap.get(vo.getId());
            if (CollectionUtils.isNotEmpty(versions)) {
                final List<ProjectComputeVersionLockVO> childrenVOS = versions.stream().map(m -> {
                    final ProjectComputeVersionLockVO childrenVo = new ProjectComputeVersionLockVO();
                    childrenVo.setId(m.getId());
                    childrenVo.setName(VERSION_PREFIX+m.getVersionNum());
                    childrenVo.setIrrAfterTax(m.getIrrAfterTax());
                    childrenVo.setNpvAfterTax(m.getNpvAfterTax());
                    childrenVo.setPbpAfterTax(m.getPbpAfterTax());
                    childrenVo.setTotalInvest(m.getTotalInvest());
                    childrenVo.setProjectId(projectInfo.getId());
                    return childrenVo;
                }).collect(Collectors.toList());
                vo.setChildren(childrenVOS);
            }
            versionLockVOS.add(vo);
        }
        dto.setCount(projectInfoDTO.getCount());
        return versionLockVOS;
    }

    @Override
    public ServiceResult lock(List<ComputeVersionDTO> dtos) {
        if (CollectionUtils.isEmpty(dtos)) {
            return CommonResultEnum.VALUE_INVALID;
        }
        final Map<String,String> projectIdVersionIdMap = dtos.stream()
                .filter(f -> StringUtils.isNotEmpty(f.getProjectId()) && StringUtils.isNotEmpty(f.getId()))
                .collect(Collectors.toMap(ComputeVersionDTO::getProjectId,ComputeVersionDTO::getId,(v1,v2)->v1));

        if (MapUtils.isEmpty(projectIdVersionIdMap)) {
            return CommonResultEnum.SUCCESS;
        }

        final ProjectInfoDTO projectInfoDTO = new ProjectInfoDTO();
        projectInfoDTO.setIdList(projectIdVersionIdMap.keySet());
        final List<ProjectInfo> projectInfos = projectInfoDAO.queryList(projectInfoDTO);
        List<ProjectInfo> projectInfoList = new ArrayList<>();
        for (ProjectInfo projectInfo : projectInfos) {
            final String computeId = projectIdVersionIdMap.get(projectInfo.getId());
            if (StringUtils.isEmpty(computeId)) {
                continue;
            }
            if (computeId.equals(projectInfo.getComputeId())) {
                continue;
            }
            projectInfo.setComputeId(computeId);
            projectInfoList.add(projectInfo);
        }
        if (CollectionUtils.isNotEmpty(projectInfoList)) {
            projectInfoDAO.updateBatchById(projectInfoList);
        }
        return CommonResultEnum.SUCCESS;
    }

}
